5  Hipóteses Lineares

Modelos lineares estão entre as ferramentas mais importantes do aprendizado de máquina. Eles são matematicamente simples, eficientes e interpretáveis, mas também servem de bloco básico para modelos mais complexos. Uma unidade de uma rede neural, por exemplo, começa calculando a mesma soma ponderada que estudaremos neste capítulo.

O termo linear não significa que a saída final precise ser uma reta. Significa que o modelo começa combinando os atributos de entrada por uma pontuação linear. Para um exemplo \(x=(x_1,\ldots,x_d)\in\mathbb R^d\), definimos

\[ s(x)=b+w_1x_1+\cdots+w_dx_d, \tag{5.1}\]

em que \(w_1,\ldots,w_d\) são os pesos e \(b\) é o viés (bias) ou intercepto. Cada peso expressa como uma variação no atributo correspondente altera a pontuação, mantendo os outros atributos fixos.

NotePeso não implica causalidade

Um peso positivo indica associação positiva dentro do modelo; não prova que o atributo causa o resultado. Dados observacionais podem conter correlações espúrias, variáveis omitidas e vieses de seleção.

5.1 Visão geral dos modelos lineares

5.1.1 Uma estrutura comum para três tarefas

Depois de calcular \(s(x)\), aplicamos uma função de saída \(h_0\):

\[ h_w(x)=h_0\!\left(s(x)\right). \]

A escolha de \(h_0\) adapta a mesma estrutura linear a diferentes tipos de problema:

Tarefa Espaço de saída Transformação Interpretação
classificação binária \(\{-1,+1\}\) \(h_0(s)=\operatorname{sinal}(s)\) escolhe uma de duas classes
regressão linear \(\mathbb R\) \(h_0(s)=s\) prevê uma quantidade
regressão logística \((0,1)\) \(h_0(s)=\sigma(s)=1/(1+e^{-s})\) estima uma probabilidade

A mesma pontuação linear pode alimentar três funções de saída diferentes.

Considere um banco que representa cada cliente por renda, dívida, tempo de emprego e histórico de pagamentos. A mesma entrada pode originar perguntas distintas:

  • classificação: o pedido deve ser aprovado?
  • regressão: qual limite de crédito é adequado?
  • probabilidade: qual é a probabilidade estimada de inadimplência?

O tipo da variável-alvo determina o modelo e a função de erro apropriada. Não faz sentido, por exemplo, interpretar diretamente uma regressão linear como probabilidade, pois sua saída pode ser menor que zero ou maior que um.

5.1.2 Notação matricial e a coordenada de viés

Podemos incorporar \(b\) ao vetor de pesos adicionando uma coordenada constante à entrada:

\[ \widetilde{x}=(1,x_1,\ldots,x_d), \qquad \widetilde{w}=(b,w_1,\ldots,w_d). \]

Então Equation 5.1 assume a forma compacta

\[ s(x)=\widetilde{w}^{\mathsf T}\widetilde{x}. \]

O sobrescrito \(\mathsf T\) indica transposição. Se os dois vetores forem tratados como colunas, \(\widetilde{w}^{\mathsf T}\) é uma linha e o produto matricial produz o escalar

\[ \widetilde{w}^{\mathsf T}\widetilde{x} =b+w_1x_1+\cdots+w_dx_d. \]

Esse “truque do \(1\)” simplifica fórmulas e implementações: o algoritmo pode atualizar viés e pesos com uma única operação vetorial. É importante, porém, lembrar que um exemplo com \(d\) atributos passa a ser representado por \(d+1\) coordenadas.

Para uma amostra com \(N\) exemplos, organizamos as entradas nas linhas da matriz de projeto

\[ X= \begin{bmatrix} 1 & x_{11} & \cdots & x_{1d}\\ 1 & x_{21} & \cdots & x_{2d}\\ \vdots & \vdots & \ddots & \vdots\\ 1 & x_{N1} & \cdots & x_{Nd} \end{bmatrix}. \]

O vetor \(X\widetilde w\) contém de uma só vez as pontuações dos \(N\) exemplos. Essa formulação é central em bibliotecas numéricas, pois substitui laços explícitos por operações matriciais otimizadas.

5.1.3 Aprender significa escolher os pesos

Seja

\[ D=\{(x_1,y_1),\ldots,(x_N,y_N)\} \]

uma amostra rotulada. Para cada vetor \(\widetilde w\), o modelo produz predições \(h_{\widetilde w}(x_n)\). Uma função de perda \(\ell(h_{\widetilde w}(x_n),y_n)\) mede o custo de cada predição, e o erro empírico é normalmente a média

\[ E_{\mathrm{in}}(\widetilde w) =\frac1N\sum_{n=1}^{N} \ell\!\left(h_{\widetilde w}(x_n),y_n\right). \]

O algoritmo de aprendizado procura pesos que reduzam esse erro:

\[ \widetilde w^{\ast} \in\operatorname*{arg\,min}_{\widetilde w} E_{\mathrm{in}}(\widetilde w). \]

Os três métodos deste capítulo diferem em dois pontos principais: a função de saída e a perda usada na otimização. O Perceptron atualiza os pesos quando encontra um exemplo classificado incorretamente; a regressão linear minimiza o erro quadrático; e a regressão logística minimiza uma perda probabilística.

5.1.4 Geometria da pontuação

O conjunto de pontos com pontuação zero,

\[ b+w_1x_1+\cdots+w_dx_d=0, \]

é um hiperplano. Em duas dimensões ele é uma reta; em três, um plano. O vetor \(w=(w_1,\ldots,w_d)\) é perpendicular a esse hiperplano, enquanto o viés controla seu deslocamento em relação à origem. Na classificação, o sinal da pontuação indica de que lado da fronteira o ponto está. Na regressão, a própria pontuação representa a altura prevista.

Essa interpretação geométrica também revela uma limitação: sem transformar os atributos, uma única fronteira linear não consegue separar padrões como o XOR. Mais adiante, transformações de atributos e redes neurais permitirão construir fronteiras não lineares a partir de componentes lineares.

5.1.5 Escala dos atributos

Os pesos dependem das unidades adotadas. Se renda estiver em centavos e idade em anos, a primeira coordenada pode ter magnitude milhões de vezes maior. Isso pode tornar a otimização instável e dificulta comparar os pesos. Uma prática comum é padronizar cada atributo numérico:

\[ x'_j=\frac{x_j-\mu_j}{\sigma_j}, \]

em que \(\mu_j\) e \(\sigma_j\) são calculados somente no conjunto de treinamento. Usar estatísticas de validação ou teste introduziria vazamento de dados.

5.1.6 O que estudaremos

Nas próximas seções, a mesma sequência será repetida para cada modelo:

  1. definir a classe de hipóteses;
  2. escolher uma função de erro;
  3. derivar ou apresentar o algoritmo de otimização;
  4. implementar o método computacionalmente;
  5. discutir convergência, limitações e uso adequado.

Ao final, será possível reconhecer que Perceptron, regressão linear e regressão logística não são técnicas isoladas. São três instâncias de uma mesma ideia: combinar atributos linearmente e adaptar a saída ao tipo de pergunta que desejamos responder.

5.2 4.1 Perceptron (ou Discriminador Linear)

O Perceptron é um algoritmo para classificação binária. Ele recebe exemplos descritos por vetores numéricos e aprende uma fronteira linear que procura separar duas classes. Apesar de simples, o método introduz ideias que reaparecem em redes neurais: soma ponderada, função de ativação e atualização iterativa dos pesos a partir dos erros.

Considere novamente a análise de crédito. Cada cliente é representado por atributos como renda, dívida e tempo de emprego, e o rótulo histórico informa se houve pagamento (\(+1\)) ou inadimplência (\(-1\)). O modelo calcula uma pontuação

\[ s(x)=w^{\mathsf T}x+b \]

e compara essa pontuação com zero:

\[ h_{w,b}(x)= \begin{cases} +1, & w^{\mathsf T}x+b\geq 0,\\ -1, & w^{\mathsf T}x+b<0. \end{cases} \tag{5.2}\]

Adotar uma regra explícita para o caso de igualdade evita que \(\operatorname{sinal}(0)\) fique indefinido na implementação. Outra convenção seria possível, desde que fosse usada de maneira consistente.

5.2.1 Interpretação da pontuação

O valor \(s(x)\) contém mais informação do que o rótulo final. Seu sinal determina a classe e seu módulo indica a distância algébrica até o limiar. Cada componente contribui com \(w_jx_j\):

  • se \(w_j>0\), valores maiores de \(x_j\) elevam a pontuação;
  • se \(w_j<0\), valores maiores de \(x_j\) reduzem a pontuação;
  • se \(w_j=0\), o atributo não participa da decisão atual.

Essa leitura exige atenção à escala. Um peso pequeno associado a um atributo medido em milhares pode ter impacto maior do que um peso grande associado a um atributo entre zero e um. Por isso, a contribuição \(w_jx_j\) costuma ser mais informativa que o peso isolado.

5.2.2 Interpretação geométrica

A fronteira de decisão contém os pontos de pontuação zero:

\[ \{x\in\mathbb R^d:w^{\mathsf T}x+b=0\}. \]

Esse conjunto é um hiperplano perpendicular ao vetor \(w\). Os pontos com pontuação positiva ficam em um semiespaço, e os de pontuação negativa, no outro.

A fronteira do Perceptron separa os dois semiespaços; o vetor de pesos é perpendicular a ela.

Em duas dimensões, com \(x=(x_1,x_2)\) e \(w_2\neq0\), podemos escrever a fronteira como uma reta:

\[ w_1x_1+w_2x_2+b=0 \quad\Longleftrightarrow\quad x_2=-\frac{w_1}{w_2}x_1-\frac{b}{w_2}. \]

Logo, \(-w_1/w_2\) é a inclinação e \(-b/w_2\) é o intercepto vertical. Alterar a direção de \(w\) gira a fronteira; alterar \(b\) a desloca sem mudar sua orientação.

5.2.3 O que o algoritmo aprende

Dada uma amostra

\[ D=\{(x_1,y_1),\ldots,(x_N,y_N)\}, \qquad y_n\in\{-1,+1\}, \]

o objetivo, quando os dados são linearmente separáveis, é encontrar \(w\) e \(b\) tais que

\[ y_n\bigl(w^{\mathsf T}x_n+b\bigr)>0 \qquad\text{para todo }n. \tag{5.3}\]

Por que essa única desigualdade representa as duas classes? Se \(y_n=+1\), ela exige pontuação positiva. Se \(y_n=-1\), multiplicar por \(-1\) inverte o sinal e exige pontuação negativa. A quantidade

\[ y_n\bigl(w^{\mathsf T}x_n+b\bigr) \]

é chamada margem funcional do exemplo: é positiva quando a classificação está correta e não positiva quando há erro ou empate.

O Perceptron não calcula a fronteira em uma única fórmula. Ele percorre os exemplos e, sempre que encontra um erro, move os parâmetros na direção que favorece o rótulo correto. As subseções seguintes irão formalizar a classe de hipóteses, o erro e essa regra de atualização.

WarningHipótese fundamental

O Perceptron clássico converge em um número finito de atualizações somente quando os dados são linearmente separáveis. Se houver ruído, rótulos contraditórios ou uma fronteira essencialmente não linear, ele pode continuar oscilando. A variante Pocket tratará esse caso.

5.2.4 Exemplos de aplicação

  • Filtro de spam: frequências de palavras formam o vetor de entrada, e o sinal da pontuação decide entre spam e mensagem legítima.
  • Controle de qualidade: medidas de uma peça alimentam uma decisão entre aprovada e defeituosa.
  • Diagnóstico assistido: atributos clínicos produzem uma triagem binária, que deve ser avaliada com atenção a custos de falsos positivos e falsos negativos.

Nesses exemplos, a decisão automatizada não deve ser confundida com uma verdade absoluta. O modelo reproduz padrões presentes na amostra e pode herdar seus erros e vieses. Em aplicações de alto impacto, métricas por subgrupo, revisão humana e documentação dos dados são partes do sistema, não detalhes opcionais.

5.2.5 Hipóteses

Uma hipótese é uma regra de classificação obtida ao fixar os parâmetros do modelo. Para evitar ambiguidade entre os atributos originais e a coordenada constante, usaremos um til na representação homogênea:

\[ x=(x_1,\ldots,x_d) \quad\longmapsto\quad \widetilde{x}=(1,x_1,\ldots,x_d), \]

\[ (b,w_1,\ldots,w_d) \quad\longmapsto\quad \widetilde{w}=(b,w_1,\ldots,w_d). \]

O produto escalar entre dois vetores coluna \(u,v\in\mathbb R^{d+1}\) é

\[ u^{\mathsf T}v=\sum_{j=0}^{d}u_jv_j. \]

Portanto,

\[ \widetilde{w}^{\mathsf T}\widetilde{x} =b+w_1x_1+\cdots+w_dx_d. \tag{5.4}\]

Essa escrita incorpora o viés na mesma operação usada para os demais pesos. Ela também evita um erro comum de orientação: se \(\widetilde w\) e \(\widetilde x\) são vetores coluna de tamanho \((d+1)\times1\), então \(\widetilde w^{\mathsf T}\widetilde x\) tem tamanho \(1\times1\) e representa um escalar. Já \(\widetilde w\widetilde x^{\mathsf T}\) seria uma matriz \((d+1)\times(d+1)\), não o produto escalar desejado.

Com a convenção de que empates recebem o rótulo \(+1\), definimos

\[ \operatorname{sinal}_{+}(z)= \begin{cases} +1, & z\geq0,\\ -1, & z<0. \end{cases} \]

A classe de hipóteses do Perceptron em \(\mathbb R^d\) é, então,

\[ \mathcal H_{mathrm{perc}} =\left\{ h_{\widetilde w}(x) =\operatorname{sinal}_{+} \!\left(\widetilde w^{\mathsf T}\widetilde x\right) :\widetilde w\in\mathbb R^{d+1} \right\}. \tag{5.5}\]

Observe a diferença entre três objetos:

  • \(\mathcal H_{\mathrm{perc}}\) é a classe de todas as fronteiras lineares permitidas;
  • \(h_{\widetilde w}\) é uma hipótese particular, determinada por um vetor de parâmetros;
  • \(g=h_{\widetilde w^*}\) é a hipótese final escolhida pelo algoritmo a partir dos dados.

5.2.6 Equivalência de parametrizações

Alguns textos escrevem a pontuação como \(w^{\mathsf T}x-b\) e chamam \(b\) de limiar. Outros escrevem \(w^{\mathsf T}x+b\) e chamam \(b\) de viés. As duas formas são equivalentes: basta trocar \(b\) por \(-b\). Neste capítulo, adotaremos a segunda convenção para manter a compatibilidade com a notação usual de regressão e redes neurais.

Por exemplo, em duas dimensões,

\[ h(x)=\operatorname{sinal}_{+}(2-3x_1+x_2) \]

possui vetor homogêneo \(\widetilde w=(2,-3,1)\). Para \(x=(1,4)\), temos \(\widetilde x=(1,1,4)\) e

\[ \widetilde w^{\mathsf T}\widetilde x =2-3(1)+1(4)=3, \]

portanto \(h(x)=+1\). Para \(x=(2,1)\), a pontuação é \(2-3(2)+1=-3\) e a previsão é \(-1\).

5.2.7 Invariância por escala positiva

Se \(c>0\), os vetores \(\widetilde w\) e \(c\widetilde w\) definem exatamente a mesma classificação, pois

\[ \operatorname{sinal}_{+} \!\left((c\widetilde w)^{\mathsf T}\widetilde x\right) = \operatorname{sinal}_{+} \!\left(c\,\widetilde w^{\mathsf T}\widetilde x\right). \]

Assim, há infinitos vetores de parâmetros que representam a mesma fronteira. Multiplicar por um número negativo, porém, troca os lados e inverte todos os rótulos. Essa redundância explica por que o tamanho bruto de \(\widetilde w\) não determina sozinho a fronteira de decisão.

5.2.8 Representação de uma amostra

Se os exemplos homogêneos forem armazenados nas linhas de \(\widetilde X\in\mathbb R^{N\times(d+1)}\), todas as pontuações podem ser calculadas por

\[ s=\widetilde X\widetilde w\in\mathbb R^N. \]

A aplicação componente a componente de \(\operatorname{sinal}_{+}\) gera o vetor de predições. Em NumPy, essa ideia corresponde essencialmente a scores = X_tilde @ w_tilde, uma operação matricial que também orientará a implementação do algoritmo.

TipTeste de dimensões

Antes de implementar uma fórmula, anote as dimensões: \(\widetilde X\) é \(N\times(d+1)\) e \(\widetilde w\) é \((d+1)\times1\); logo, o produto é \(N\times1\), uma pontuação por exemplo.

5.2.9 Erro

Para avaliar uma hipótese de classificação, a medida mais direta é contar quantas previsões discordam dos rótulos. A perda zero–um de um exemplo é

\[ \ell_{0\text{-}1}(h(x_n),y_n) =\mathbb 1\!\left[h(x_n)\neq y_n\right], \]

em que \(\mathbb 1[Q]\) vale \(1\) quando a proposição \(Q\) é verdadeira e \(0\) quando é falsa. O número total de erros na amostra é

\[ N_{\mathrm{erro}}(h) =\sum_{n=1}^{N} \mathbb 1\!\left[h(x_n)\neq y_n\right], \]

e a taxa de erro dentro da amostra é

\[ E_{\mathrm{in}}(h) =\frac{1}{N}N_{\mathrm{erro}}(h). \tag{5.6}\]

A contagem e a taxa contêm a mesma informação quando \(N\) é fixo. A taxa é geralmente preferível porque permanece entre zero e um e permite comparar amostras de tamanhos diferentes.

5.2.10 Erro escrito com rótulos \(\{-1,+1\}\)

Como \(h(x_n)\) e \(y_n\) pertencem a \(\{-1,+1\}\), sua diferença é zero em um acerto e \(\pm2\) em um erro. Logo,

\[ \mathbb 1\!\left[h(x_n)\neq y_n\right] =\frac{\left(h(x_n)-y_n\right)^2}{4}. \]

O fator \(1/4\) é indispensável: sem ele, cada erro seria contado como quatro. Portanto, uma forma equivalente de Equation 5.6 é

\[ E_{\mathrm{in}}(h) =\frac{1}{4N}\sum_{n=1}^{N} \left(h(x_n)-y_n\right)^2. \]

Essa equivalência depende especificamente da codificação \(\{-1,+1\}\). Com rótulos \(\{0,1\}\), o quadrado da diferença já vale um nos erros.

5.2.11 Margem e condição de erro

Para o Perceptron, é mais conveniente expressar o erro antes de aplicar a função sinal. Defina a margem funcional do exemplo \(n\) por

\[ m_n=y_n\left(w^{\mathsf T}x_n+b\right). \]

Com a convenção adotada para empates, um exemplo é certamente classificado de modo correto quando \(m_n>0\). Quando \(m_n<0\), ele está do lado errado da fronteira. Em \(m_n=0\), a perda zero–um depende do rótulo e da regra de desempate. O algoritmo clássico adota um critério mais conservador e solicita uma atualização para qualquer margem não positiva:

\[ \ell_{\mathrm{perc}}(m_n)=\mathbb 1[m_n\leq0]. \tag{5.7}\]

O critério conservador de atualização muda abruptamente quando a margem cruza zero.

O módulo de \(m_n\) não altera esse critério: uma classificação correta por margem \(0{,}001\) e outra por margem \(100\) recebem perda zero. Esse comportamento é adequado para medir acurácia, mas fornece pouca informação para otimização.

5.2.12 Por que não minimizar diretamente a perda zero–um?

A função em degrau de Equation 5.7 é descontínua em zero e constante em quase todos os demais pontos. Seu gradiente é zero onde existe e não está definido no salto. Consequentemente, métodos de gradiente não recebem uma direção útil para mover os pesos.

O Perceptron contorna esse problema com uma regra operacional simples: seleciona um exemplo com \(m_n\leq0\) e ajusta os pesos para aumentar sua margem. Essa regra será derivada na próxima subseção. Outros modelos substituem a perda zero–um por funções contínuas, como a perda logística ou a hinge loss.

5.2.13 Separabilidade e valor mínimo

Se existe \((w,b)\) para o qual \(m_n>0\) para todo \(n\), a amostra é linearmente separável e o mínimo da taxa de erro é zero. Nesse caso, o teorema de convergência do Perceptron garante que o algoritmo encontra uma solução em número finito de atualizações.

Se os dados não são separáveis, então nenhuma hipótese da classe alcança erro zero. O Perceptron clássico pode visitar diferentes vetores de peso sem estabilizar. Isso não significa que todos sejam igualmente bons: alguns cometem menos erros que outros. A variante Pocket guardará no “bolso” o melhor vetor observado durante a execução.

ImportantErro de treinamento não é erro de generalização

Mesmo quando \(E_{\mathrm{in}}(h)=0\), ainda é necessário avaliar a hipótese em dados não usados no ajuste. Uma fronteira pode separar a amostra por acaso, especialmente quando há poucos exemplos ou muitos atributos.

5.2.14 Acurácia e custos assimétricos

A acurácia é \(1-E_{\mathrm{in}}(h)\), mas nem sempre resume o objetivo da aplicação. Em diagnóstico médico, deixar de detectar uma doença pode ser mais grave do que gerar um alarme falso; em filtros de spam, bloquear uma mensagem legítima pode ter custo elevado. Nesses casos, além da taxa de erro, devem ser examinadas a matriz de confusão, precisão, revocação e uma função de custo coerente com o problema.

5.2.14.1 Verificação rápida

Considere rótulos verdadeiros \((+1,+1,-1,-1)\) e previsões \((+1,-1,-1,+1)\). Há dois erros em quatro exemplos, portanto \(N_{\mathrm{erro}}=2\), \(E_{\mathrm{in}}=0{,}5\) e a acurácia é \(0{,}5\). Pela fórmula quadrática, a soma dos quadrados é \(0+4+0+4=8\); dividindo por \(4N=16\), obtemos novamente \(0{,}5\).

5.2.15 Algoritmo

O algoritmo do Perceptron constrói os parâmetros por correções locais. Começamos com um vetor, frequentemente \(\widetilde w^{(0)}=0\). Na iteração \(t\), escolhemos um exemplo \((\widetilde x_n,y_n)\) cuja margem não é positiva:

\[ y_n\left(\widetilde w^{(t)}\right)^{\mathsf T} \widetilde x_n\leq0. \tag{5.8}\]

Em seguida, atualizamos

\[ \widetilde w^{(t+1)} =\widetilde w^{(t)}+\eta y_n\widetilde x_n, \tag{5.9}\]

em que \(\eta>0\) é a taxa de aprendizado. No Perceptron clássico, \(\eta=1\) é suficiente; deixar o parâmetro explícito ajuda a interpretar o tamanho do passo e aproxima a notação da usada em outros métodos.

5.2.16 Por que a atualização aponta para o lado correto?

Se \(y_n=+1\), somamos \(\eta\widetilde x_n\) aos pesos, aumentando a pontuação desse exemplo. Se \(y_n=-1\), subtraímos \(\eta\widetilde x_n\), reduzindo sua pontuação. Em ambos os casos, a nova margem é

\[ \begin{aligned} m_n^{(t+1)} &=y_n\left(\widetilde w^{(t+1)}\right)^{\mathsf T}\widetilde x_n\\ &=y_n\left(\widetilde w^{(t)}+\eta y_n\widetilde x_n\right)^{\mathsf T} \widetilde x_n\\ &=m_n^{(t)}+\eta y_n^2\widetilde x_n^{\mathsf T}\widetilde x_n\\ &=m_n^{(t)}+\eta\|\widetilde x_n\|_2^2. \end{aligned} \tag{5.10}\]

Usamos \(y_n^2=1\). Como \(\eta>0\) e \(\|\widetilde x_n\|_2^2>0\), a margem do exemplo selecionado sempre aumenta.

Uma atualização aumenta a margem do exemplo que provocou a correção.

Essa garantia é local: a atualização pode reduzir a margem de outros exemplos e até fazer uma previsão antes correta tornar-se incorreta. O teorema de convergência não afirma que o número de erros diminui a cada passo; afirma que, sob separabilidade, esse processo de correções não pode continuar para sempre.

5.2.17 Atualizando viés e pesos separadamente

Como \(\widetilde x_n=(1,x_n)\) e \(\widetilde w=(b,w)\), Equation 5.9 equivale a

\[ \begin{aligned} b^{(t+1)}&=b^{(t)}+\eta y_n,\\ w^{(t+1)}&=w^{(t)}+\eta y_nx_n. \end{aligned} \]

Essa forma é útil quando a implementação armazena o viés separado. Se os atributos forem transformados ou normalizados, a coordenada constante não deve ser normalizada junto com eles.

5.2.18 Pseudocódigo

entrada: amostra D, taxa η > 0, limite de épocas
inicialize w e b

para cada época:
    número_de_atualizações ← 0
    para cada (x_n, y_n) em D:
        margem ← y_n (wᵀ x_n + b)
        se margem ≤ 0:
            w ← w + η y_n x_n
            b ← b + η y_n
            número_de_atualizações ← número_de_atualizações + 1
    se número_de_atualizações = 0:
        encerre: todos os exemplos têm margem positiva

devolva w e b

Uma época é uma passagem completa pela amostra. O contador de atualizações fornece um critério de parada mais confiável que verificar se o vetor mudou “pouco”: no Perceptron, ausência de atualizações durante uma época significa que todos os exemplos foram classificados corretamente segundo o critério adotado.

5.2.19 Ordem dos exemplos

A solução encontrada não é única e pode depender da ordem em que os exemplos são apresentados. Em implementações práticas, é comum embaralhar a amostra a cada época. Isso evita padrões artificiais na ordem dos dados e pode acelerar a convergência, embora não altere a hipótese matemática de separabilidade.

Há duas variantes de seleção frequentes:

  • on-line ou estocástica: atualiza imediatamente ao encontrar cada erro;
  • por erro escolhido: localiza algum exemplo incorreto, atualiza e reinicia a busca.

Ambas seguem a mesma regra fundamental. A primeira costuma ser mais natural para dados recebidos em fluxo.

5.2.20 Taxa de aprendizado e inicialização

Para dados separáveis e taxa positiva constante, mudar \(\eta\) ou a escala da inicialização frequentemente altera o representante numérico, mas não a essência da busca por uma fronteira. Ainda assim, valores extremos podem causar problemas de ponto flutuante. Inicializar em zero é válido para um único Perceptron, diferentemente de redes neurais com várias unidades simétricas.

WarningSempre imponha um limite de execução

Se a amostra não for separável, o critério “pare quando não houver erros” pode nunca ser satisfeito. Uma implementação robusta recebe um número máximo de épocas ou atualizações e registra a melhor solução observada.

5.2.21 Convergência não é generalização

Quando o algoritmo encerra com zero erros, sabemos apenas que encontrou uma fronteira consistente com a amostra. O desempenho em exemplos novos depende da representatividade dos dados e da complexidade da classe. A convergência é uma propriedade do procedimento de otimização; a generalização é uma propriedade estatística avaliada fora do conjunto de treinamento.

5.2.22 Código

Uma implementação deve tornar explícitas decisões que o pseudocódigo matemático costuma omitir: formato dos dados, critério para empates, limite de épocas, embaralhamento e informações devolvidas ao usuário. O código abaixo usa NumPy e armazena o viés separadamente dos pesos.

from dataclasses import dataclass

import numpy as np


@dataclass
class ResultadoPerceptron:
    pesos: np.ndarray
    vies: float
    epocas: int
    atualizacoes: int
    convergiu: bool
    erros_por_epoca: list[int]


def treinar_perceptron(
    X,
    y,
    *,
    taxa=1.0,
    max_epocas=1_000,
    embaralhar=True,
    semente=0,
):
    """Treina um classificador Perceptron binário.

    X deve ter forma (n_exemplos, n_atributos) e y deve conter
    somente os rótulos -1 e +1.
    """
    X = np.asarray(X, dtype=float)
    y = np.asarray(y, dtype=int)

    if X.ndim != 2:
        raise ValueError("X deve ser uma matriz bidimensional")
    if y.ndim != 1 or len(y) != len(X):
        raise ValueError("y deve ter um rótulo para cada linha de X")
    if not np.all(np.isin(y, (-1, 1))):
        raise ValueError("os rótulos devem pertencer a {-1, +1}")
    if taxa <= 0 or max_epocas <= 0:
        raise ValueError("taxa e max_epocas devem ser positivos")

    rng = np.random.default_rng(semente)
    pesos = np.zeros(X.shape[1], dtype=float)
    vies = 0.0
    atualizacoes = 0
    erros_por_epoca = []

    for epoca in range(1, max_epocas + 1):
        indices = np.arange(len(X))
        if embaralhar:
            rng.shuffle(indices)

        erros = 0
        for i in indices:
            margem = y[i] * (X[i] @ pesos + vies)
            if margem <= 0:
                pesos += taxa * y[i] * X[i]
                vies += taxa * y[i]
                erros += 1
                atualizacoes += 1

        erros_por_epoca.append(erros)
        if erros == 0:
            return ResultadoPerceptron(
                pesos, vies, epoca, atualizacoes, True,
                erros_por_epoca
            )

    return ResultadoPerceptron(
        pesos, vies, max_epocas, atualizacoes, False,
        erros_por_epoca
    )

O uso de argumentos nomeados após * reduz enganos como trocar a taxa de aprendizado pelo número de épocas. A semente torna o embaralhamento reproduzível, algo importante em experimentos e depuração.

5.2.23 Predição

Treinamento e predição devem ser funções separadas. Isso permite aplicar os mesmos parâmetros a conjuntos de treino, validação e teste.

def prever_perceptron(X, pesos, vies):
    X = np.asarray(X, dtype=float)
    pontuacoes = X @ pesos + vies
    # Mesma convenção do capítulo: empate recebe +1.
    return np.where(pontuacoes >= 0, 1, -1)


def taxa_de_erro(y_real, y_predito):
    y_real = np.asarray(y_real)
    y_predito = np.asarray(y_predito)
    return np.mean(y_real != y_predito)

5.2.24 Exemplo reproduzível

X = np.array([
    [-2.0, 4.0],
    [ 4.0, 1.0],
    [ 1.0, 6.0],
    [ 2.0, 4.0],
    [ 6.0, 2.0],
])
y = np.array([-1, -1, 1, 1, 1])

resultado = treinar_perceptron(
    X,
    y,
    taxa=1.0,
    max_epocas=1_000,
    embaralhar=True,
    semente=42,
)

predicoes = prever_perceptron(
    X, resultado.pesos, resultado.vies
)

print("pesos:", resultado.pesos)
print("viés:", resultado.vies)
print("convergiu:", resultado.convergiu)
print("erro de treino:", taxa_de_erro(y, predicoes))

Se resultado.convergiu for falso, não se deve interpretar o último vetor como necessariamente o melhor. Ele é apenas o estado no instante em que o limite foi atingido. A seção sobre o algoritmo Pocket mostrará como guardar os parâmetros de menor erro.

5.2.25 Visualização em duas dimensões

Quando há exatamente dois atributos e \(w_2\neq0\), a fronteira \(w_1x_1+w_2x_2+b=0\) pode ser desenhada como \(x_2=-(w_1x_1+b)/w_2\):

import matplotlib.pyplot as plt


def desenhar_fronteira_2d(X, y, pesos, vies):
    fig, ax = plt.subplots()

    positivos = y == 1
    ax.scatter(
        X[positivos, 0], X[positivos, 1],
        marker="o", label="+1"
    )
    ax.scatter(
        X[~positivos, 0], X[~positivos, 1],
        marker="x", label="-1"
    )

    limite_x = np.array(ax.get_xlim())
    if not np.isclose(pesos[1], 0.0):
        limite_y = -(pesos[0] * limite_x + vies) / pesos[1]
        ax.plot(limite_x, limite_y, label="fronteira")
    else:
        ax.axvline(-vies / pesos[0], label="fronteira")

    ax.set_xlabel("atributo 1")
    ax.set_ylabel("atributo 2")
    ax.legend()
    return fig, ax


desenhar_fronteira_2d(
    X, y, resultado.pesos, resultado.vies
)
plt.show()

O caso pesos[1] == 0 merece tratamento próprio, pois a fronteira é vertical e a fórmula de inclinação dividiria por zero.

TipEvite vazamento no pré-processamento

Se os atributos forem padronizados, ajuste médias e desvios apenas nos dados de treinamento. Aplique depois a mesma transformação aos dados de validação, teste e produção.

5.2.25.1 Questões para experimentar

  1. Execute o treinamento com sementes diferentes. Os pesos finais são iguais? As previsões na amostra são iguais?
  2. Remova max_epocas de uma implementação ingênua e insira dois exemplos idênticos com rótulos opostos. O que acontece?
  3. Compare o histórico erros_por_epoca com a taxa de erro calculada depois de cada época. Por que o número de atualizações durante uma época não precisa ser igual ao erro dos parâmetros ao final dela?

5.2.26 Exemplo em dois passos

Vamos acompanhar um caso pequeno o bastante para verificar cada conta. Considere os pontos bidimensionais

\[ p=(0,2),\qquad y_p=+1, \]

\[ q=(1,1),\qquad y_q=-1. \]

Na representação homogênea,

\[ \widetilde p=(1,0,2), \qquad \widetilde q=(1,1,1). \]

Escolha como estado inicial \(\widetilde w^{(0)}=(0,0,2)\). A primeira coordenada é o viés; as duas restantes são os pesos dos atributos. A fronteira inicial satisfaz

\[ 0+0x_1+2x_2=0, \]

isto é, \(x_2=0\).

5.2.26.1 Passo 1: localizar o erro

As pontuações iniciais são

\[ \left(\widetilde w^{(0)}\right)^{\mathsf T}\widetilde p =0+0(0)+2(2)=4, \]

\[ \left(\widetilde w^{(0)}\right)^{\mathsf T}\widetilde q =0+0(1)+2(1)=2. \]

O ponto \(p\) é positivo e recebeu pontuação positiva, portanto está correto. O ponto \(q\) é negativo, mas também recebeu pontuação positiva. Sua margem confirma o erro:

\[ m_q^{(0)} =y_q\left(\widetilde w^{(0)}\right)^{\mathsf T}\widetilde q =(-1)(2)=-2<0. \]

5.2.26.2 Passo 2: atualizar e verificar

Com taxa \(\eta=1\), usamos \(q\) para atualizar:

\[ \begin{aligned} \widetilde w^{(1)} &=\widetilde w^{(0)}+y_q\widetilde q\\ &=(0,0,2)-(1,1,1)\\ &=(-1,-1,1). \end{aligned} \]

A nova fronteira é

\[ -1-x_1+x_2=0 \quad\Longleftrightarrow\quad x_2=x_1+1. \]

Agora, as pontuações são

\[ \left(\widetilde w^{(1)}\right)^{\mathsf T}\widetilde p =-1-1(0)+1(2)=1, \]

\[ \left(\widetilde w^{(1)}\right)^{\mathsf T}\widetilde q =-1-1(1)+1(1)=-1. \]

Logo, \(p\) recebe \(+1\) e \(q\) recebe \(-1\). Uma única atualização foi suficiente para separar a amostra.

A correção causada por q transforma a fronteira horizontal em uma reta que separa os dois pontos.

Podemos conferir diretamente a identidade da melhora de margem. Como \(\|\widetilde q\|^2=1^2+1^2+1^2=3\),

\[ m_q^{(1)} =m_q^{(0)}+\|\widetilde q\|^2 =-2+3=1, \]

que coincide com \(y_q(\widetilde w^{(1)})^{\mathsf T}\widetilde q=(-1)(-1)=1\).

NotePor que o título diz dois passos?

Os dois passos são diagnosticar o exemplo incorreto e aplicar a correção. Há apenas uma atualização de pesos. Distinguir iteração, atualização e época evita confusão ao analisar o tempo de execução.

5.2.26.3 Exercício de extensão

Refaça as contas começando com \(\widetilde w^{(0)}=(0,0,0)\) e percorrendo primeiro \(p\) e depois \(q\). Registre, após cada atualização, as pontuações, as margens e a equação da fronteira.

5.2.27 Tempo de Execução

Há dois custos diferentes a considerar: o custo de uma operação e o número de operações até a convergência.

Para um exemplo com \(d\) atributos, calcular \(w^{\mathsf T}x+b\) custa \(O(d)\). Uma passagem por \(N\) exemplos custa \(O(Nd)\); portanto, executar \(K\) épocas tem custo \(O(KNd)\) e requer \(O(d)\) de memória para os parâmetros, além da memória usada para armazenar ou transmitir os dados.

Esse cálculo não informa quanto vale \(K\). Para dados separáveis, o teorema de convergência do Perceptron fornece uma cota para o número de atualizações, baseada na geometria da amostra.

5.2.28 Raio e margem

Usaremos os vetores homogêneos \(\widetilde x_n\) para incluir o viés. Suponha que exista um vetor unitário \(u\), com \(\|u\|_2=1\), que separe a amostra com margem \(\gamma>0\):

\[ y_nu^{\mathsf T}\widetilde x_n\geq\gamma \qquad\text{para todo }n. \tag{5.11}\]

Defina também o raio

\[ R=\max_{1\leq n\leq N}\|\widetilde x_n\|_2. \tag{5.12}\]

Como \(u\) é unitário, \(|u^{\mathsf T}\widetilde x|\) é a distância assinada do ponto ao hiperplano \(u^{\mathsf T}\widetilde x=0\). A margem \(\gamma\) é a menor distância assinada, depois de corrigir o lado com \(y_n\); é o ponto mais próximo que limita a folga da separação.

A margem é determinada pelos exemplos mais próximos da fronteira.

Para uma fronteira na forma não normalizada \(w^{\mathsf T}x+b=0\), a distância geométrica de um ponto \(x\) é

\[ \operatorname{dist}(x,H) =\frac{|w^{\mathsf T}x+b|}{\|w\|_2}. \]

O denominador é \(\|w\|_2\), e não \(\|w\|_2^2\). Essa fórmula decorre da projeção sobre a direção normal \(w/\|w\|_2\). Recordando o produto escalar,

\[ v^{\mathsf T}z=\|v\|_2\,\|z\|_2\cos\theta, \]

em que \(\theta\) é o ângulo entre os vetores.

5.2.29 Teorema de convergência

NoteTeorema de convergência do Perceptron

Considere \(\widetilde w^{(0)}=0\), taxa \(\eta=1\) e uma amostra que satisfaz Equation 5.11 e Equation 5.12. O Perceptron comete no máximo

\[ T\leq\left(\frac{R}{\gamma}\right)^2 \]

atualizações antes de encontrar uma separação correta.

A cota depende da razão \(R/\gamma\). Uma margem grande facilita o problema; exemplos com normas muito grandes aumentam a cota. Isso também ajuda a entender por que escalonar atributos pode melhorar o comportamento numérico.

5.2.30 Ideia da demonstração

Depois de \(T\) atualizações, cada uma provocada por \((\widetilde x_t,y_t)\), temos

\[ \widetilde w^{(T)} =\sum_{t=1}^{T}y_t\widetilde x_t. \]

Projetando o vetor acumulado sobre a direção da solução \(u\),

\[ u^{\mathsf T}\widetilde w^{(T)} =\sum_{t=1}^{T}y_tu^{\mathsf T}\widetilde x_t \geq T\gamma. \tag{5.13}\]

Por Cauchy–Schwarz e \(\|u\|=1\),

\[ u^{\mathsf T}\widetilde w^{(T)} \leq\|\widetilde w^{(T)}\|_2. \]

Agora limitamos o crescimento da norma. Como uma atualização ocorre quando \(y_t(\widetilde w^{(t)})^{\mathsf T}\widetilde x_t\leq0\),

\[ \begin{aligned} \|\widetilde w^{(t+1)}\|_2^2 &=\|\widetilde w^{(t)}+y_t\widetilde x_t\|_2^2\\ &=\|\widetilde w^{(t)}\|_2^2 +2y_t(\widetilde w^{(t)})^{\mathsf T}\widetilde x_t +\|\widetilde x_t\|_2^2\\ &\leq\|\widetilde w^{(t)}\|_2^2+R^2. \end{aligned} \]

Somando as \(T\) atualizações,

\[ \|\widetilde w^{(T)}\|_2^2\leq TR^2, \qquad \|\widetilde w^{(T)}\|_2\leq\sqrt{T}R. \tag{5.14}\]

Combinando Equation 5.13 e Equation 5.14,

\[ T\gamma\leq\sqrt{T}R \quad\Longrightarrow\quad T\leq\frac{R^2}{\gamma^2}. \]

O argumento mostra um contraste: o alinhamento com a solução cresce linearmente em \(T\), enquanto a norma cresce no máximo como \(\sqrt{T}\). Se as atualizações continuassem além da cota, as duas desigualdades seriam incompatíveis.

5.2.31 O que a cota não diz

  • Ela limita atualizações, não necessariamente épocas. Uma época pode conter nenhuma, uma ou várias atualizações.
  • É uma cota de pior caso; a execução real pode terminar muito antes.
  • Ela exige separabilidade com margem positiva. Com dados não separáveis, não há garantia de término.
  • Ela não afirma que o Perceptron encontra a fronteira de margem máxima. Métodos como máquinas de vetores de suporte perseguem esse objetivo de forma explícita.
  • Ela não é uma garantia de generalização; apenas prova convergência no conjunto de treinamento.

5.2.32 Relação com o custo total

No modo on-line, cada exemplo custa \(O(d)\) e o teorema limita a quantidade de correções a \((R/\gamma)^2\). Porém, encontrar uma época sem erros ainda requer verificar os exemplos. Para uma implementação por épocas, a medida mais transparente continua sendo

\[ O(KNd), \]

registrando separadamente \(K\) e o número total de atualizações. Essa distinção evita interpretar a cota teórica como se fosse diretamente o tempo de relógio do programa.

5.2.32.1 Exercícios

  1. O que acontece com a cota se todos os vetores de entrada forem multiplicados por uma constante positiva \(c\)? Considere também como a margem se transforma.
  2. Mostre em qual passo da demonstração a separabilidade é usada.
  3. Uma execução fez 80 atualizações em 12 épocas. Quais desses números podem ser comparados diretamente com \((R/\gamma)^2\)?

5.2.33 Animação

Uma animação ajuda a desfazer uma interpretação enganosa: o Perceptron não move a fronteira continuamente em direção a uma reta ideal. A cada erro, ele salta para um novo vetor de parâmetros. A fronteira pode girar, transladar e até voltar a classificar incorretamente um ponto que estava correto.

Para acompanhar o processo, cada quadro deve mostrar pelo menos:

  • os pontos e seus rótulos verdadeiros;
  • a fronteira atual \(w^{\mathsf T}x+b=0\);
  • o exemplo que provocou a atualização;
  • o número da época e da atualização;
  • a taxa de erro ou o número de erros dos parâmetros atuais.

5.2.34 Registrando os quadros

O gerador abaixo é uma versão compacta do treinamento. Ele produz um estado depois de cada correção, sem armazenar todos os quadros simultaneamente.

import numpy as np


def quadros_perceptron(X, y, max_epocas=100):
    X = np.asarray(X, dtype=float)
    y = np.asarray(y, dtype=int)
    w = np.zeros(X.shape[1])
    b = 0.0
    atualizacao = 0

    # Quadro inicial.
    yield {
        "epoca": 0,
        "atualizacao": 0,
        "indice": None,
        "w": w.copy(),
        "b": b,
    }

    for epoca in range(1, max_epocas + 1):
        houve_atualizacao = False

        for i, (x_i, y_i) in enumerate(zip(X, y)):
            if y_i * (w @ x_i + b) <= 0:
                w += y_i * x_i
                b += y_i
                atualizacao += 1
                houve_atualizacao = True

                yield {
                    "epoca": epoca,
                    "atualizacao": atualizacao,
                    "indice": i,
                    "w": w.copy(),
                    "b": b,
                }

        if not houve_atualizacao:
            return

O método copy() é importante. Sem ele, todos os dicionários poderiam referenciar o mesmo vetor mutável e parecer conter apenas o estado final. Esse é um erro frequente ao registrar históricos numéricos em Python.

5.2.35 Construindo a animação

Para dados bidimensionais, podemos transformar os estados em uma animação com matplotlib.animation.FuncAnimation:

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation


def animar_perceptron(X, y, max_epocas=100, intervalo=700):
    estados = list(quadros_perceptron(X, y, max_epocas))
    fig, ax = plt.subplots()

    positivos = y == 1
    ax.scatter(X[positivos, 0], X[positivos, 1], label="+1")
    ax.scatter(
        X[~positivos, 0], X[~positivos, 1],
        marker="x", label="-1"
    )
    destaque = ax.scatter([], [], s=180, facecolors="none",
                          edgecolors="black")
    fronteira, = ax.plot([], [], color="black")
    titulo = ax.set_title("")
    ax.legend()

    xmin, xmax = ax.get_xlim()
    ymin, ymax = ax.get_ylim()
    eixo_x = np.array([xmin, xmax])

    def atualizar(estado):
        w, b = estado["w"], estado["b"]

        if not np.isclose(w[1], 0.0):
            eixo_y = -(w[0] * eixo_x + b) / w[1]
            fronteira.set_data(eixo_x, eixo_y)
        elif not np.isclose(w[0], 0.0):
            x_vertical = -b / w[0]
            fronteira.set_data([x_vertical, x_vertical], [ymin, ymax])
        else:
            fronteira.set_data([], [])

        i = estado["indice"]
        destaque.set_offsets(
            np.empty((0, 2)) if i is None else X[[i]]
        )
        titulo.set_text(
            f"época {estado['epoca']} · "
            f"atualização {estado['atualizacao']}"
        )
        return fronteira, destaque, titulo

    animacao = FuncAnimation(
        fig,
        atualizar,
        frames=estados,
        interval=intervalo,
        repeat=False,
    )
    return fig, animacao

Em um notebook, o resultado pode ser exibido como HTML:

from IPython.display import HTML

fig, animacao = animar_perceptron(X, y)
plt.close(fig)
HTML(animacao.to_jshtml())

Para salvar em GIF ou vídeo, o Matplotlib precisa de um escritor compatível instalado no ambiente. A exibição em to_jshtml() evita essa dependência e costuma ser suficiente para experimentos didáticos.

5.2.36 O que observar

Ao executar a animação, responda:

  1. Toda atualização reduz o número total de erros?
  2. O exemplo destacado fica correto imediatamente após sua atualização?
  3. Quantas atualizações ocorrem em cada época?
  4. A fronteira final muda quando a ordem dos exemplos muda?
  5. O comportamento se torna mais estável após padronizar os atributos?
NoteAnimação não é prova

A visualização produz intuição e ajuda a depurar uma implementação, mas mostra apenas uma amostra e uma ordem de apresentação. A garantia de convergência vem do argumento matemático da seção anterior.

5.2.37 O Algoritmo Pocket (= bolso)

O Perceptron clássico foi projetado para encontrar uma separação perfeita. Quando a amostra não é linearmente separável, suas atualizações continuam, e o último vetor visitado pode ser pior que vetores encontrados anteriormente. O algoritmo Pocket acrescenta memória ao processo: ele mantém no “bolso” os parâmetros com menor erro observados até então.

Essa modificação é útil quando há ruído de medição, rótulos incorretos, exemplos contraditórios ou uma fronteira verdadeira não linear. Nesses casos, exigir \(E_{\mathrm{in}}=0\) é impossível ou indesejável.

5.2.37.1 Estado corrente e estado guardado

O Pocket mantém dois vetores distintos:

  • \(\widetilde w_{\mathrm{atual}}\), que continua recebendo as atualizações do Perceptron;
  • \(\widetilde w_{\mathrm{melhor}}\), que representa o menor erro de treinamento encontrado até aquele instante.

Depois de cada atualização do estado corrente, calculamos

\[ E_{\mathrm{in}}(\widetilde w) =\frac1N\sum_{n=1}^{N} \mathbb 1\!\left[ h_{\widetilde w}(x_n)\neq y_n \right]. \]

Se o novo erro for menor que o erro guardado, copiamos os parâmetros para o bolso. Como o melhor estado só é substituído por outro melhor, sua sequência de erros é monotonicamente não crescente, mesmo que o estado corrente oscile.

O estado corrente pode piorar, enquanto o menor erro guardado pelo Pocket nunca aumenta.

É indispensável copiar o vetor. Em Python, a atribuição melhor_w = w pode criar apenas outra referência para o mesmo array; atualizações futuras alterariam também o conteúdo do bolso.

5.2.37.2 Pseudocódigo

inicialize w_atual
w_melhor ← cópia de w_atual
erro_melhor ← erro_de_treino(w_melhor)

repita até atingir o limite de atualizações:
    escolha um exemplo com margem não positiva
    se nenhum existir:
        encerre: erro zero foi alcançado

    aplique uma atualização do Perceptron em w_atual
    erro_atual ← erro_de_treino(w_atual)

    se erro_atual < erro_melhor:
        w_melhor ← cópia de w_atual
        erro_melhor ← erro_atual

devolva w_melhor

Um limite de atualizações é parte da especificação, não apenas uma proteção acidental: em dados não separáveis, não existe um instante natural no qual o Perceptron necessariamente pare.

5.2.37.3 Implementação

import numpy as np


def erro_classificacao(X, y, w, b):
    predicoes = np.where(X @ w + b >= 0, 1, -1)
    return np.mean(predicoes != y)


def treinar_pocket(
    X,
    y,
    *,
    max_atualizacoes=10_000,
    taxa=1.0,
    semente=0,
):
    X = np.asarray(X, dtype=float)
    y = np.asarray(y, dtype=int)
    rng = np.random.default_rng(semente)

    w = np.zeros(X.shape[1])
    b = 0.0
    melhor_w = w.copy()
    melhor_b = b
    melhor_erro = erro_classificacao(X, y, w, b)

    for atualizacao in range(1, max_atualizacoes + 1):
        margens = y * (X @ w + b)
        candidatos = np.flatnonzero(margens <= 0)

        if len(candidatos) == 0:
            return melhor_w, melhor_b, melhor_erro, atualizacao - 1

        i = rng.choice(candidatos)
        w += taxa * y[i] * X[i]
        b += taxa * y[i]

        erro_atual = erro_classificacao(X, y, w, b)
        if erro_atual < melhor_erro:
            melhor_w = w.copy()
            melhor_b = b
            melhor_erro = erro_atual

    return melhor_w, melhor_b, melhor_erro, max_atualizacoes

Essa versão escolhe aleatoriamente um exemplo problemático. O uso de uma semente permite reproduzir a trajetória. Em caso de empate no erro, poderíamos manter o vetor mais antigo, preferir a maior margem média ou usar um critério de validação; a decisão deve ser documentada.

5.2.37.4 Custo computacional

Uma atualização custa \(O(d)\), mas recalcular o erro sobre todos os exemplos custa \(O(Nd)\). Se essa avaliação ocorrer depois de cada uma das \(T\) atualizações, o custo é \(O(TNd)\). Por isso, implementações para bases grandes podem avaliar o bolso a cada certo número de passos ou manter estruturas auxiliares. Essas otimizações alteram a frequência com que bons estados podem ser registrados.

5.2.37.5 O que o Pocket garante — e o que não garante

O algoritmo devolve uma solução não pior que qualquer estado que ele tenha guardado, segundo o critério usado. Entretanto:

  • ele não garante encontrar o mínimo global da perda zero–um;
  • mais iterações ampliam a busca, mas não estabelecem quando o ótimo foi encontrado;
  • escolher pelo erro de treinamento não garante o menor erro fora da amostra;
  • testar repetidamente no conjunto de teste para decidir o bolso causa vazamento de dados.

Se desejarmos escolher o número de atualizações ou desempatar modelos com base em desempenho externo, devemos usar um conjunto de validação e reservar o teste para a avaliação final.

5.2.37.6 Perceptron versus Pocket

Aspecto Perceptron clássico Pocket
estado devolvido último estado melhor estado observado
separável converge para erro zero também pode alcançar erro zero
não separável pode oscilar devolve uma aproximação encontrada
memória extra \(O(d)\) \(O(d)\) para a cópia adicional
avaliação de erro não é necessária a cada passo usualmente custa \(O(Nd)\)
garantia de ótimo global não não
ImportantO bolso preserva, mas não otimiza sozinho

O mérito do Pocket é não perder uma boa solução durante uma trajetória oscilante. A qualidade final ainda depende dos estados explorados pelo Perceptron, do orçamento de atualizações e da ordem dos exemplos.

5.2.38 Recapitulação

O Perceptron reúne em um único exemplo várias ideias fundamentais do aprendizado de máquina. Os dados fornecem exemplos rotulados; uma classe de hipóteses delimita as fronteiras permitidas; uma medida de erro avalia as previsões; e um algoritmo ajusta parâmetros com base nos exemplos em que a hipótese atual falha.

5.2.38.1 Mapa da seção

Elemento Formulação no Perceptron
entrada \(x\in\mathbb R^d\)
rótulo \(y\in\{-1,+1\}\)
pontuação \(s(x)=w^{\mathsf T}x+b\)
hipótese \(h(x)=\operatorname{sinal}_{+}(s(x))\)
fronteira \(w^{\mathsf T}x+b=0\)
margem funcional \(y(w^{\mathsf T}x+b)\)
condição de atualização \(y(w^{\mathsf T}x+b)\leq0\)
atualização \(w\leftarrow w+\eta yx\), \(b\leftarrow b+\eta y\)
erro empírico média de \(\mathbb 1[h(x_n)\neq y_n]\)
hipótese de convergência amostra linearmente separável
cota de atualizações \(T\leq(R/\gamma)^2\)

O vetor \(w\) é perpendicular à fronteira, enquanto \(b\) controla seu deslocamento. Adicionar uma coordenada constante permite escrever ambos como um único vetor homogêneo \(\widetilde w\).

5.2.38.2 O fluxo do treinamento

  1. Inicialize os parâmetros.
  2. Calcule a margem de um exemplo.
  3. Se a margem não for positiva, atualize na direção \(y x\).
  4. Repita até completar uma época sem atualizações ou atingir o limite de execução.
  5. Avalie a hipótese resultante em dados que não participaram do ajuste.

Para dados separáveis, o Perceptron termina com erro de treinamento zero. Para dados não separáveis, o estado corrente pode oscilar; o Pocket preserva o estado de menor erro encontrado durante uma execução finita.

WarningQuatro conclusões que não são válidas
  • Uma atualização não precisa diminuir o erro total da amostra.
  • Convergir não significa encontrar a fronteira de maior margem.
  • Erro de treinamento zero não implica erro de teste zero.
  • Um peso de grande módulo não prova que o atributo é causalmente importante.

5.2.38.3 Questões conceituais

  1. Qual é a diferença entre a perda zero–um e o critério de atualização baseado em margem não positiva?
  2. Por que \(y(w^{\mathsf T}x+b)>0\) representa corretamente as duas classes em uma única desigualdade?
  3. O que acontece geometricamente quando alteramos apenas \(b\)? E quando alteramos a direção de \(w\)?
  4. Por que a atribuição melhor_w = w pode invalidar uma implementação do Pocket em NumPy?
  5. Em qual hipótese o teorema de convergência depende? Dê um exemplo de amostra que viola essa hipótese.
  6. O número de erros necessariamente diminui após cada atualização? Justifique com a natureza local da regra.

5.2.38.4 Problemas de aplicação

  1. Uma atualização. Para \(x=(2,-1)\), \(y=-1\), \(w=(1,3)\), \(b=0\) e \(\eta=0{,}5\), calcule a margem. Determine se há atualização e, se houver, obtenha os novos parâmetros.
  2. Fronteira. Escreva a equação da reta definida por \(w=(2,-4)\) e \(b=8\). Identifique inclinação e intercepto.
  3. XOR. Represente os quatro pontos binários \((0,0),(0,1),(1,0),(1,1)\), rotulando como positiva a paridade ímpar. Explique geometricamente por que uma única reta não separa as classes.
  4. Complexidade. Uma base possui \(N=50\,000\) exemplos e \(d=200\) atributos. Quantos produtos peso–atributo são necessários, aproximadamente, para dez épocas completas?
  5. Cota. Se \(R=5\) e \(\gamma=0{,}25\), calcule a cota de atualizações. Explique por que o valor não prediz exatamente o tempo observado.

5.2.38.5 Respostas breves para conferência

  1. No primeiro problema, a pontuação é \(-1\), a margem é \(1\) e não há atualização.
  2. A reta é \(2x_1-4x_2+8=0\), ou \(x_2=0{,}5x_1+2\).
  3. No XOR, classes iguais ocupam vértices opostos; qualquer reta deixa pelo menos um vértice no lado incompatível.
  4. Dez épocas exigem aproximadamente \(10\cdot50\,000\cdot200=10^8\) multiplicações, além de somas e outros custos.
  5. A cota é \((5/0{,}25)^2=400\) atualizações e representa um pior caso sob as hipóteses do teorema.

Com esse vocabulário consolidado, podemos passar da decisão binária para a previsão de valores reais. A regressão linear manterá a pontuação \(w^{\mathsf T}x+b\), mas substituirá a função sinal e a regra de atualização por uma função de erro diferenciável.

5.3 4.2 A Regressão Linear

A classificação responde a perguntas categóricas, como “aprovar ou rejeitar?”. Muitos sistemas, porém, precisam prever uma quantidade: o consumo de energia na próxima hora, o tempo de execução de um programa, o preço de um imóvel ou o limite de crédito adequado a um cliente. A regressão linear é o modelo mais simples para esse tipo de saída.

Em um problema de regressão, cada exemplo é um par

\[ (x_n,y_n), \qquad x_n\in\mathbb R^d, \quad y_n\in\mathbb R, \]

em que \(x_n\) contém os atributos e \(y_n\) é o valor-alvo observado. A amostra é

\[ D=\{(x_1,y_1),\ldots,(x_N,y_N)\}. \]

O modelo atribui a cada entrada uma previsão real

\[ \widehat y=h_{w,b}(x)=w^{\mathsf T}x+b. \tag{5.15}\]

O símbolo “chapéu” distingue a previsão \(\widehat y\) do valor observado \(y\). A diferença

\[ e_n=y_n-\widehat y_n \]

é o resíduo do exemplo \(n\). Resíduo positivo significa que o modelo previu abaixo do valor observado; resíduo negativo significa que previu acima.

A regressão escolhe uma reta que aproxima os valores observados; os segmentos tracejados são resíduos.

5.3.1 Da reta ao hiperplano

Com um único atributo, Equation 5.15 descreve uma reta:

\[ \widehat y=b+wx. \]

O peso \(w\) é a inclinação: aumentar \(x\) em uma unidade altera a previsão em \(w\) unidades. O viés \(b\) é a previsão quando \(x=0\), embora essa interpretação só seja relevante se zero fizer sentido no domínio.

Com dois atributos, o gráfico da previsão é um plano; com \(d\) atributos, é um hiperplano em dimensão \(d+1\). Não conseguimos visualizá-lo diretamente quando \(d\) é grande, mas a álgebra permanece a mesma.

5.3.2 Um exemplo: tempo de execução

Suponha que desejemos prever o tempo de um algoritmo a partir do tamanho da entrada \(n\) e de uma medida de densidade \(r\). Um modelo possível é

\[ \widehat t=0{,}4+0{,}015n+1{,}8r. \]

Para \(n=100\) e \(r=0{,}5\), a previsão é

\[ \widehat t=0{,}4+0{,}015(100)+1{,}8(0{,}5)=2{,}8. \]

Se o tempo observado for \(3{,}1\) segundos, o resíduo é \(3{,}1-2{,}8=0{,}3\) segundo. Uma única diferença não determina a qualidade do modelo; precisamos resumir os resíduos de toda a amostra.

5.3.3 O que significa “melhor reta”?

Em geral, nenhuma reta passa por todos os pontos. Precisamos definir como comparar erros positivos e negativos e quanto penalizar grandes desvios. A regressão linear clássica escolhe os parâmetros que minimizam a soma ou a média dos quadrados dos resíduos:

\[ \operatorname{MSE}(w,b) =\frac1N\sum_{n=1}^{N} \left(y_n-w^{\mathsf T}x_n-b\right)^2. \]

O quadrado impede cancelamento entre sinais e penaliza fortemente erros grandes. Além disso, produz uma função diferenciável e convexa dos parâmetros, permitindo obter uma solução global por álgebra linear ou por métodos iterativos.

NoteLinear nos parâmetros

Uma regressão pode incluir atributos transformados e continuar linear nos parâmetros. Por exemplo, \(\widehat y=w_0+w_1x+w_2x^2\) é curva em \(x\), mas é linear no vetor \((w_0,w_1,w_2)\) quando usamos os atributos \((1,x,x^2)\).

5.3.4 Previsão, associação e causalidade

Um coeficiente positivo indica que, dentro do modelo e mantendo os outros atributos constantes, valores maiores daquele atributo estão associados a previsões maiores. Isso não demonstra causalidade. Uma regressão pode usar correlações úteis para prever mesmo quando não identifica o processo que gera o resultado.

Em decisões de crédito, saúde ou políticas públicas, essa distinção é crítica: dados históricos podem refletir desigualdades, decisões humanas anteriores e variáveis omitidas. Desempenho preditivo deve ser analisado junto com procedência dos dados, métricas por subgrupo e consequências do uso do modelo.

5.3.5 Suposições e limites iniciais

A regressão linear é uma aproximação apropriada quando uma combinação linear captura parte relevante do sinal. Problemas comuns incluem:

  • não linearidade: os resíduos exibem um padrão sistemático;
  • valores atípicos: o quadrado dá influência elevada a erros grandes;
  • extrapolação: previsões longe da faixa observada podem ser implausíveis;
  • multicolinearidade: atributos quase redundantes tornam coeficientes instáveis;
  • mudança de distribuição: relações aprendidas no passado podem não persistir em produção.

As próximas subseções formalizam a classe de hipóteses, a função de erro e os dois caminhos principais para calcular os parâmetros: solução algébrica por mínimos quadrados e otimização iterativa.

5.3.6 Hipóteses

Nesta subseção, hipótese significa uma função candidata dentro da classe de modelos. Não deve ser confundida com as hipóteses estatísticas sobre ruído, independência ou variância que podem ser usadas para fazer inferência sobre os coeficientes.

Para \(d\) atributos, a classe da regressão linear com intercepto é

\[ \mathcal H_{mathrm{lin}} =\left\{ h_{w,b}:\mathbb R^d\to\mathbb R \;\middle|\; h_{w,b}(x)=w^{\mathsf T}x+b, \;w\in\mathbb R^d, \;b\in\mathbb R \right\}. \tag{5.16}\]

Cada escolha de \((w,b)\) define uma hipótese diferente. O algoritmo de aprendizado selecionará uma delas usando a amostra.

5.3.7 Representação homogênea

Como no Perceptron, podemos introduzir

\[ \widetilde x=(1,x_1,\ldots,x_d), \qquad \widetilde w=(b,w_1,\ldots,w_d), \]

e escrever

\[ h_{\widetilde w}(x) =\widetilde x^{\mathsf T}\widetilde w. \tag{5.17}\]

A ordem do produto é apenas uma convenção quando ambos representam vetores e o resultado é escalar. Para manter coerência com a matriz de projeto, trataremos cada exemplo homogêneo como um vetor linha. Assim, \(\widetilde x^{\mathsf T}\widetilde w\) na notação abstrata corresponde a uma linha multiplicada pelo vetor coluna de parâmetros na implementação.

Mais precisamente, se \(\widetilde x\) for definido como vetor coluna, usamos \(\widetilde x^{\mathsf T}\widetilde w\); se for armazenado como linha, a transposição já está implícita. O importante é verificar as dimensões, não decorar a posição de um sobrescrito.

5.3.8 Da hipótese individual à matriz de projeto

Organizamos os \(N\) exemplos nas linhas da matriz de projeto:

\[ \widetilde X= \begin{bmatrix} 1 & x_{11} & x_{12} & \cdots & x_{1d}\\ 1 & x_{21} & x_{22} & \cdots & x_{2d}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 1 & x_{N1} & x_{N2} & \cdots & x_{Nd} \end{bmatrix} \in\mathbb R^{N\times(d+1)}. \]

O vetor de alvos é

\[ y= \begin{bmatrix} y_1\\y_2\\\vdots\\y_N \end{bmatrix} \in\mathbb R^N, \]

e o vetor de previsões de uma hipótese é

\[ \widehat y =\widetilde X\widetilde w \in\mathbb R^N. \tag{5.18}\]

As dimensões confirmam a operação:

\[ \underbrace{\widetilde X}_{N\times(d+1)} \underbrace{\widetilde w}_{(d+1)\times1} = \underbrace{\widehat y}_{N\times1}. \]

Cada linha da multiplicação reproduz \(\widehat y_n=b+w_1x_{n1}+\cdots+w_dx_{nd}\).

5.3.9 Vetor de resíduos

Reunindo os resíduos de todos os exemplos,

\[ e=y-\widehat y =y-\widetilde X\widetilde w. \tag{5.19}\]

A regressão por mínimos quadrados escolherá \(\widetilde w\) para tornar a norma \(\|e\|_2\) pequena. Geometricamente, ela mede desvios na direção do eixo de saída \(y\), não a menor distância perpendicular entre cada ponto e a reta. Essa distinção é importante: a regressão linear usual supõe que os atributos são dados e o erro está associado à variável de saída.

5.3.10 O papel de cada coeficiente

Para

\[ h(x)=b+w_1x_1+\cdots+w_dx_d, \]

o coeficiente \(w_j\) é a variação na previsão causada por aumentar \(x_j\) em uma unidade mantendo os demais atributos constantes. Suas unidades são

\[ [w_j]=\frac{[y]}{[x_j]}. \]

Se \(y\) é medido em reais e \(x_j\) em metros quadrados, por exemplo, \(w_j\) é medido em reais por metro quadrado. Padronizar atributos muda a escala numérica dos coeficientes, mas não precisa mudar as previsões após a transformação inversa correta.

WarningIntercepto não deve ser removido automaticamente

Forçar \(b=0\) obriga o hiperplano a passar pela origem. Isso só é justificável quando a teoria do problema exige saída zero para entrada zero. Caso contrário, a restrição pode introduzir viés sistemático nos resíduos.

5.3.11 Linearidade e engenharia de atributos

A classe pode ser enriquecida substituindo \(x\) por um vetor de características \(\phi(x)\):

\[ h_w(x)=w^{\mathsf T}\phi(x). \]

Com \(\phi(x)=(1,x,x^2)\), obtemos uma regressão polinomial quadrática. Com indicadores binários, podemos representar categorias; com produtos \(x_ix_j\), podemos representar interações. O modelo continua linear nos parâmetros \(w\), embora a relação com a entrada original possa ser curva.

Essa flexibilidade tem custo: adicionar muitas características aumenta a capacidade do modelo, o consumo de memória e o risco de sobreajuste. Transformações devem ser definidas usando apenas informações disponíveis no instante da previsão.

5.3.11.1 Verificação computacional das formas

import numpy as np

X = np.array([
    [100.0, 0.2],
    [250.0, 0.7],
    [400.0, 0.9],
])
y = np.array([1.8, 5.2, 7.1])

X_tilde = np.column_stack([np.ones(len(X)), X])
w_tilde = np.array([0.4, 0.015, 1.8])
y_predito = X_tilde @ w_tilde
residuos = y - y_predito

print(X_tilde.shape)   # (3, 3)
print(w_tilde.shape)   # (3,)
print(y_predito.shape) # (3,)

Em NumPy, um array com shape == (3,) não é explicitamente linha nem coluna. O operador @ aplica as regras adequadas, mas, ao combinar matrizes mais complexas, declarar formas como (3, 1) pode tornar a intenção mais clara.

5.3.12 Erro

A função de erro transforma um vetor de resíduos em um único número. Na regressão linear clássica, usamos o erro quadrático médio (mean squared error, MSE):

\[ E_{\mathrm{in}}(\widetilde w) =\operatorname{MSE}(\widetilde w) =\frac1N\sum_{n=1}^{N} \left(y_n-\widetilde x_n^{\mathsf T}\widetilde w\right)^2. \tag{5.20}\]

A palavra “médio” corresponde ao fator \(1/N\). Não há uma integral sobre a amostra finita; há uma média empírica das perdas individuais.

O quadrado desempenha três papéis:

  • torna todos os termos não negativos, impedindo o cancelamento entre resíduos positivos e negativos;
  • penaliza resíduos grandes mais intensamente;
  • produz uma função suave e convexa dos parâmetros.

5.3.13 Soma, média e raiz do erro quadrático

A soma dos quadrados dos resíduos é

\[ \operatorname{SSE}(\widetilde w) =\sum_{n=1}^{N}e_n^2. \]

Como \(\operatorname{MSE}=\operatorname{SSE}/N\) e \(N\) não depende dos parâmetros, SSE e MSE possuem exatamente os mesmos minimizadores. Seus valores, porém, não são intercambiáveis ao relatar resultados.

A raiz do MSE é

\[ \operatorname{RMSE} =\sqrt{\frac1N\sum_{n=1}^{N}e_n^2}. \]

MSE tem unidades de \(y^2\), enquanto RMSE tem as mesmas unidades do alvo. Se o alvo é medido em segundos, por exemplo, o RMSE também é expresso em segundos e costuma ser mais fácil de interpretar.

5.3.14 Forma matricial

Pela Equation 5.19,

\[ e=y-\widetilde X\widetilde w. \]

A norma euclidiana satisfaz

\[ \|e\|_2^2=e^{\mathsf T}e=\sum_{n=1}^{N}e_n^2. \]

Assim, Equation 5.20 pode ser escrita de modo compacto:

\[ E_{\mathrm{in}}(\widetilde w) =\frac1N \left\|y-\widetilde X\widetilde w\right\|_2^2. \tag{5.21}\]

Expandindo o produto,

\[ E_{\mathrm{in}}(\widetilde w) =\frac1N \left( y^{\mathsf T}y -2\widetilde w^{\mathsf T}\widetilde X^{\mathsf T}y +\widetilde w^{\mathsf T}\widetilde X^{\mathsf T} \widetilde X\widetilde w \right). \tag{5.22}\]

Essa é uma função quadrática de \(\widetilde w\). Sua matriz Hessiana é proporcional a \(\widetilde X^{\mathsf T}\widetilde X\), que é positiva semidefinida. Portanto, todo mínimo local é global. A unicidade dependerá do posto da matriz de projeto, assunto da subseção sobre o algoritmo.

5.3.15 MSE versus MAE

Outra medida comum é o erro absoluto médio (mean absolute error, MAE):

\[ \operatorname{MAE} =\frac1N\sum_{n=1}^{N}|e_n|. \]

A perda quadrática atribui influência crescente aos resíduos de grande módulo.
Propriedade MSE/RMSE MAE
crescimento da perda quadrático linear
sensibilidade a valores atípicos maior menor
diferenciabilidade em zero sim não
estimativa central associada média condicional mediana condicional
unidade reportada MSE: quadrada; RMSE: original original

Nenhuma métrica é universalmente superior. A escolha deve refletir o custo real dos erros. Se dobrar o erro deve custar quatro vezes mais, o quadrado é coerente; se o custo cresce aproximadamente de modo linear, o MAE pode representar melhor a aplicação.

5.3.16 Efeito de um valor atípico

Considere resíduos \((1,-1,2,10)\). Temos

\[ \operatorname{MAE} =\frac{1+1+2+10}{4}=3{,}5, \]

enquanto

\[ \operatorname{MSE} =\frac{1+1+4+100}{4}=26{,}5. \]

O último exemplo responde por \(100/106\approx94{,}3\%\) da soma quadrática. Isso pode ser desejável quando grandes erros são realmente graves, ou prejudicial quando o ponto resulta de falha de medição. Valores atípicos devem ser investigados, não removidos automaticamente.

5.3.17 Coeficiente de determinação

Uma métrica complementar é

\[ R^2 =1- \frac{\sum_n(y_n-\widehat y_n)^2} {\sum_n(y_n-\overline y)^2}, \]

em que \(\overline y\) é a média dos alvos do conjunto avaliado. O numerador é o erro do modelo e o denominador é o erro do preditor constante \(\overline y\).

  • \(R^2=1\) indica previsões perfeitas naquele conjunto;
  • \(R^2=0\) indica desempenho igual ao preditor da média;
  • \(R^2<0\) significa que o modelo é pior que esse preditor de referência.

Logo, \(R^2\) não é uma porcentagem de previsões corretas e não precisa ficar entre zero e um em dados de teste.

5.3.18 Avaliação correta

Métricas de treinamento medem ajuste, não generalização. MSE, RMSE, MAE e \(R^2\) devem ser calculados também em dados não usados no treinamento. Ao comparar modelos, use a mesma partição e o mesmo pré-processamento.

WarningNão escolha a métrica depois de ver o resultado

Selecionar a métrica que faz um modelo parecer melhor introduz viés na avaliação. Defina antecipadamente a medida principal com base no custo da aplicação e use métricas secundárias para diagnóstico.

5.3.18.1 Verificação computacional

import numpy as np

y = np.array([3.0, 5.0, 7.0, 20.0])
y_predito = np.array([2.0, 6.0, 5.0, 10.0])
residuos = y - y_predito

mse = np.mean(residuos ** 2)
rmse = np.sqrt(mse)
mae = np.mean(np.abs(residuos))

print(f"MSE = {mse:.2f}")
print(f"RMSE = {rmse:.2f}")
print(f"MAE = {mae:.2f}")

No próximo passo, minimizaremos Equation 5.21 para obter os coeficientes da regressão.

5.3.19 Algoritmo

Treinar a regressão linear significa resolver o problema de mínimos quadrados

\[ \widetilde w^* \in\operatorname*{arg\,min}_{\widetilde w\in\mathbb R^{d+1}} \frac1N \left\|y-\widetilde X\widetilde w\right\|_2^2. \tag{5.23}\]

Escrevemos \(\operatorname*{arg\,min}\) porque o resultado é o conjunto de parâmetros que atingem o menor valor. Quando a solução é única, podemos tratá-lo como um único vetor \(\widetilde w^*\).

O fator \(1/N\) não altera o minimizador, por isso as derivações podem trabalhar com a soma dos quadrados. Ele continua importante ao comparar o valor do erro entre amostras de tamanhos diferentes.

5.3.20 Visão geral da solução

Sob condições que garantem a inversibilidade de \(\widetilde X^{\mathsf T}\widetilde X\), a solução pode ser escrita como

\[ \widetilde w^* =\left(\widetilde X^{\mathsf T}\widetilde X\right)^{-1} \widetilde X^{\mathsf T}y. \tag{5.24}\]

Essa expressão é chamada solução das equações normais. Ela será obtida de duas maneiras:

  1. geometricamente: \(\widetilde X\widetilde w^*\) é a projeção ortogonal de \(y\) sobre o espaço gerado pelas colunas de \(\widetilde X\);
  2. por diferenciação: no mínimo, o gradiente do erro em relação aos parâmetros é zero.

Os dois argumentos produzem a mesma condição:

\[ \widetilde X^{\mathsf T} \left(y-\widetilde X\widetilde w^*\right)=0. \tag{5.25}\]

Essa equação diz que o vetor de resíduos é ortogonal a cada coluna da matriz de projeto. Em particular, quando há uma coluna de uns para o intercepto, a soma dos resíduos de treinamento é zero, salvo efeitos de arredondamento numérico.

5.3.21 Fórmula matemática versus algoritmo numérico

É tentador implementar diretamente a inversa de \(\widetilde X^{\mathsf T}\widetilde X\). Em software numérico, essa raramente é a melhor opção. Formar o produto pode piorar o condicionamento, e calcular uma inversa explícita realiza trabalho desnecessário.

As estratégias usuais incluem:

  • resolver o sistema linear das equações normais sem formar a inversa;
  • usar fatoração QR, geralmente mais estável;
  • usar decomposição em valores singulares (SVD), que também trata posto deficiente e produz a pseudoinversa;
  • aplicar gradiente descendente ou métodos estocásticos quando a matriz é grande demais para a solução direta.

Assim, “regressão linear possui fórmula fechada” não significa que toda implementação deva calcular essa fórmula literalmente.

5.3.22 Quando a solução é única?

Se as \(d+1\) colunas de \(\widetilde X\) são linearmente independentes, então

\[ \operatorname{posto}(\widetilde X)=d+1 \]

e \(\widetilde X^{\mathsf T}\widetilde X\) é positiva definida e invertível. Nesse caso, o minimizador é único.

Se há uma coluna redundante, mais atributos que informação independente ou categorias codificadas de forma redundante, a matriz pode ter posto deficiente. Ainda existem previsões de mínimos quadrados, mas vários vetores de coeficientes podem produzir o mesmo ajuste. A pseudoinversa de Moore–Penrose seleciona, entre eles, a solução de menor norma.

ImportantNunca use a inversa como teste de existência

Se inv(X.T @ X) falhar, isso não significa que a regressão não possa ser ajustada. Use um solucionador de mínimos quadrados, como numpy.linalg.lstsq, que lida com matrizes retangulares e informa o posto estimado.

5.3.23 Complexidade em linhas gerais

Para \(N\) exemplos e \(p=d+1\) parâmetros, armazenar a matriz densa custa \(O(Np)\). Uma solução direta por QR custa tipicamente \(O(Np^2)\) quando \(N\geq p\), além de \(O(p^2)\) de memória auxiliar. Em problemas com muitos exemplos ou muitos atributos esparsos, métodos iterativos podem ser mais adequados.

Também é preciso considerar o condicionamento. Atributos em escalas muito diferentes ou quase colineares podem tornar os coeficientes extremamente sensíveis a pequenas perturbações, mesmo quando o cálculo termina sem erro.

5.3.24 Transposição e dimensões

Para \(A\in\mathbb R^{m\times n}\), a transposta \(A^{\mathsf T}\in\mathbb R^{n\times m}\) troca linhas por colunas. No nosso problema,

\[ \widetilde X^{\mathsf T}\widetilde X \in\mathbb R^{p\times p}, \qquad \widetilde X^{\mathsf T}y \in\mathbb R^p. \]

Portanto, as equações normais formam um sistema quadrado com \(p\) incógnitas. Anotar essas dimensões é uma verificação simples contra erros de orientação em código e em demonstrações.

As duas subseções seguintes desenvolvem primeiro a interpretação por projeção e depois a derivação pelo gradiente.

5.3.24.1 Aproximação por Projeção

A interpretação por projeção ocorre em \(\mathbb R^N\), o espaço que possui uma coordenada para cada exemplo. O vetor-alvo

\[ y=(y_1,\ldots,y_N)^{\mathsf T} \]

é um ponto nesse espaço. Para cada escolha de parâmetros, o vetor de previsões é \(\widetilde X\widetilde w\). Quais vetores de previsão são possíveis?

5.3.24.1.1 O espaço coluna

Escreva a matriz de projeto em termos de suas colunas:

\[ \widetilde X= \begin{bmatrix} \vert & \vert & & \vert\\ c_0 & c_1 & \cdots & c_d\\ \vert & \vert & & \vert \end{bmatrix}. \]

Então

\[ \widetilde X\widetilde w =w_0c_0+w_1c_1+\cdots+w_dc_d. \]

Logo, o conjunto de todas as previsões possíveis é o espaço gerado pelas colunas de \(\widetilde X\):

\[ \operatorname{Col}(\widetilde X) =\{\widetilde X\widetilde w: \widetilde w\in\mathbb R^{d+1}\} \subseteq\mathbb R^N. \]

Mesmo que o modelo tenha poucos parâmetros, cada previsão sobre a amostra inteira é um vetor com \(N\) componentes. Por isso, o hiperplano da figura original no espaço de atributos e o espaço coluna usado nesta derivação são objetos diferentes.

5.3.24.1.2 A previsão ótima é uma projeção

Minimizar

\[ \left\|y-\widetilde X\widetilde w\right\|_2 \]

significa encontrar o ponto de \(\operatorname{Col}(\widetilde X)\) mais próximo de \(y\). Esse ponto é a projeção ortogonal \(\widehat y=P_{widetilde X}y\).

O vetor-alvo é decomposto na previsão, que pertence ao espaço coluna, e no resíduo ortogonal.

O resíduo ótimo

\[ e^*=y-\widehat y =y-\widetilde X\widetilde w^* \]

é perpendicular a todo vetor do espaço coluna. Em particular, é perpendicular a cada coluna de \(\widetilde X\):

\[ \widetilde X^{\mathsf T}e^*=0. \]

Substituindo a definição do resíduo,

\[ \widetilde X^{\mathsf T} \left(y-\widetilde X\widetilde w^*\right)=0, \]

e obtemos as equações normais

\[ \widetilde X^{\mathsf T}\widetilde X\widetilde w^* =\widetilde X^{\mathsf T}y. \tag{5.26}\]

5.3.24.1.3 Por que a ortogonalidade garante o mínimo?

Considere qualquer outro vetor de parâmetros \(\widetilde w=\widetilde w^*+\Delta\). Seu resíduo é

\[ y-\widetilde X\widetilde w =e^*-\widetilde X\Delta. \]

O primeiro termo é perpendicular ao espaço coluna, e o segundo pertence a esse espaço. Pelo teorema de Pitágoras,

\[ \left\|e^*-\widetilde X\Delta\right\|_2^2 =\|e^*\|_2^2+\|\widetilde X\Delta\|_2^2 \geq\|e^*\|_2^2. \]

Portanto, nenhuma outra previsão possível fica mais perto de \(y\). A igualdade pode ocorrer para \(\Delta\neq0\) somente se \(\widetilde X\Delta=0\), isto é, se a matriz possui um núcleo não trivial e os parâmetros não são únicos.

5.3.24.1.4 Caso de posto completo

Se as colunas de \(\widetilde X\) são linearmente independentes, \(\widetilde X^{\mathsf T}\widetilde X\) é invertível. Isolando os parâmetros em Equation 5.26,

\[ \widetilde w^* =\left(\widetilde X^{\mathsf T}\widetilde X\right)^{-1} \widetilde X^{\mathsf T}y. \]

A matriz de projeção sobre o espaço coluna é, nesse caso,

\[ P_{widetilde X} =\widetilde X \left(\widetilde X^{\mathsf T}\widetilde X\right)^{-1} \widetilde X^{\mathsf T}, \]

pois \(\widehat y=\widetilde X\widetilde w^*=P_{\widetilde X}y\). Ela satisfaz

\[ P_{\widetilde X}^{\mathsf T}=P_{\widetilde X}, \qquad P_{\widetilde X}^2=P_{\widetilde X}, \]

propriedades de simetria e idempotência características de uma projeção ortogonal.

5.3.24.1.5 Posto deficiente e pseudoinversa

Ter \(N>d+1\) não garante independência das colunas. Dois atributos podem ser duplicados ou um pode ser combinação dos demais. Quando \(\widetilde X^{\mathsf T}\widetilde X\) não é invertível, usamos a pseudoinversa de Moore–Penrose:

\[ \widetilde w^*=\widetilde X^+y. \]

Nesse caso, \(\widetilde X^+\) não deve ser definida automaticamente por \((\widetilde X^{\mathsf T}\widetilde X)^{-1}\widetilde X^{\mathsf T}\), pois essa expressão exige justamente a inversibilidade. A definição geral é construída, por exemplo, pela SVD e devolve a solução de mínimos quadrados com menor norma euclidiana.

5.3.24.1.6 Exemplo numérico

Considere um atributo \(x=(0,1,2)^{\mathsf T}\), alvos \(y=(1,2,2)^{\mathsf T}\) e intercepto:

\[ \widetilde X= \begin{bmatrix} 1&0\\1&1\\1&2 \end{bmatrix}. \]

As equações normais produzem

\[ \widetilde w^*= \begin{bmatrix}7/6\\1/2\end{bmatrix}, \qquad \widehat y= \begin{bmatrix}7/6\\5/3\\13/6\end{bmatrix}. \]

O vetor de resíduos é

\[ e^*=y-\widehat y =\begin{bmatrix}-1/6\\1/3\\-1/6\end{bmatrix}. \]

Podemos verificar a ortogonalidade com as duas colunas:

\[ \begin{bmatrix}1&1&1\end{bmatrix}e^*=0, \qquad \begin{bmatrix}0&1&2\end{bmatrix}e^*=0. \]

O primeiro resultado diz que os resíduos somam zero; o segundo, que não resta componente residual na direção do atributo \(x\).

TipDiagnóstico útil

Em uma regressão com intercepto ajustada por mínimos quadrados, uma soma de resíduos de treinamento muito diferente de zero pode indicar erro de implementação, falta da coluna de intercepto ou precisão numérica muito ruim.

5.3.24.2 Aproximação por Derivação

A mesma solução pode ser obtida tratando o MSE como uma função diferenciável dos parâmetros. O ponto de partida é

\[ E(\widetilde w) =\frac1N\sum_{n=1}^{N} \left(y_n-\widetilde x_n^{\mathsf T}\widetilde w\right)^2. \]

Antes de usar notação matricial, derivaremos cada coordenada. Isso torna visível a origem de todos os fatores e sinais.

5.3.24.2.1 Derivação por coordenadas

Para o parâmetro \(w_j\), a regra da cadeia fornece

\[ \begin{aligned} \frac{\partial E}{\partial w_j} &=\frac1N\sum_{n=1}^{N} 2\left(y_n-\widetilde x_n^{\mathsf T}\widetilde w\right) \frac{\partial}{\partial w_j} \left(y_n-\widetilde x_n^{\mathsf T}\widetilde w\right)\\ &=-\frac2N\sum_{n=1}^{N} \widetilde x_{nj} \left(y_n-\widetilde x_n^{\mathsf T}\widetilde w\right). \end{aligned} \]

Se definirmos \(e=y-\widetilde X\widetilde w\), reunir todas as derivadas parciais produz

\[ \nabla E(\widetilde w) =-\frac2N\widetilde X^{\mathsf T}e =\frac2N\widetilde X^{\mathsf T} \left(\widetilde X\widetilde w-y\right). \tag{5.27}\]

As dimensões são consistentes: \(\widetilde X^{\mathsf T}\) é \((d+1)\times N\) e o vetor de resíduos é \(N\times1\), portanto o gradiente tem \(d+1\) componentes.

5.3.24.2.2 Derivação pela forma quadrática

Também podemos expandir o MSE:

\[ \begin{aligned} E(\widetilde w) &=\frac1N \left(y-\widetilde X\widetilde w\right)^{\mathsf T} \left(y-\widetilde X\widetilde w\right)\\ &=\frac1N\left( y^{\mathsf T}y -2\widetilde w^{\mathsf T}\widetilde X^{\mathsf T}y +\widetilde w^{\mathsf T}\widetilde X^{\mathsf T} \widetilde X\widetilde w \right). \end{aligned} \]

Usamos as identidades

\[ (AB)^{\mathsf T}=B^{\mathsf T}A^{\mathsf T}, \qquad (A^{\mathsf T})^{\mathsf T}=A, \]

e o fato de que um escalar é igual à sua transposta. Para uma matriz simétrica \(A\),

\[ \nabla_w(w^{\mathsf T}Aw)=2Aw. \]

Como \(\widetilde X^{\mathsf T}\widetilde X\) é simétrica, chegamos novamente a Equation 5.27.

5.3.24.2.3 Condição de primeira ordem

Em qualquer mínimo diferenciável não restrito, o gradiente deve ser nulo. Igualando Equation 5.27 a zero,

\[ \widetilde X^{\mathsf T} \left(\widetilde X\widetilde w^*-y\right)=0, \]

ou

\[ \widetilde X^{\mathsf T}\widetilde X\widetilde w^* =\widetilde X^{\mathsf T}y. \]

São exatamente as equações normais obtidas pela projeção. Se \(\widetilde X^{\mathsf T}\widetilde X\) for invertível,

\[ \widetilde w^* =\left(\widetilde X^{\mathsf T}\widetilde X\right)^{-1} \widetilde X^{\mathsf T}y. \]

Se ela não for invertível, a igualdade do gradiente ainda caracteriza os minimizadores, mas não podemos isolar uma solução única por meio da inversa.

5.3.24.2.4 Por que um ponto estacionário é mínimo global?

Zerar o gradiente, sozinho, não basta para qualquer função: pontos estacionários também podem ser máximos ou selas. Aqui, a Hessiana é

\[ \nabla^2E(\widetilde w) =\frac2N\widetilde X^{\mathsf T}\widetilde X. \tag{5.28}\]

Para qualquer vetor \(v\),

\[ v^{\mathsf T}\nabla^2E(\widetilde w)v =\frac2N v^{\mathsf T}\widetilde X^{\mathsf T}\widetilde Xv =\frac2N\|\widetilde Xv\|_2^2 \geq0. \]

Logo, a Hessiana é positiva semidefinida e \(E\) é convexa. Toda solução das equações normais é um mínimo global. Se \(\widetilde X\) tem posto completo de colunas, a desigualdade é estrita para \(v\neq0\), a Hessiana é positiva definida e o mínimo é único.

5.3.24.2.5 O gradiente como soma de contribuições

A fórmula

\[ \nabla E(\widetilde w) =-\frac2N\sum_{n=1}^{N}e_n\widetilde x_n \]

mostra que cada exemplo contribui com seu resíduo multiplicado pelos atributos. Um erro grande exerce influência maior; atributos de grande escala também podem produzir componentes grandes no gradiente. Essa é uma razão prática para padronizar entradas antes de usar métodos iterativos.

Se não quisermos resolver o sistema diretamente, podemos usar

\[ \widetilde w^{(t+1)} =\widetilde w^{(t)} -\eta\nabla E(\widetilde w^{(t)}), \]

o gradiente descendente. Diferentemente do Perceptron, a atualização agora deriva explicitamente de uma função de erro suave.

5.3.24.2.6 Verificação no caso de uma reta

Para \(\widehat y_n=b+wx_n\),

\[ E(b,w)=\frac1N\sum_n(y_n-b-wx_n)^2. \]

As duas equações de primeira ordem são

\[ \frac{\partial E}{\partial b} =-\frac2N\sum_n(y_n-b-wx_n)=0, \]

\[ \frac{\partial E}{\partial w} =-\frac2N\sum_nx_n(y_n-b-wx_n)=0. \]

A primeira afirma que os resíduos somam zero; a segunda, que os resíduos são ortogonais ao vetor dos valores \(x_n\). São precisamente as duas verificações feitas no exemplo da projeção.

NoteDuas linguagens para o mesmo fato

Na linguagem geométrica, o resíduo é ortogonal ao espaço coluna. Na linguagem do cálculo, o gradiente é zero. Como o gradiente é \(-2\widetilde X^{\mathsf T}e/N\), as afirmações são equivalentes.

5.3.24.3 Exercícios

  1. Derive Equation 5.27 usando a convenção \(E=\|\widetilde X\widetilde w-y\|^2/(2N)\). O que muda?
  2. Mostre que \(\widetilde X^{\mathsf T}\widetilde X\) é sempre simétrica.
  3. Explique por que posto deficiente produz uma direção \(v\neq0\) com curvatura zero em Equation 5.28.

5.3.25 Computação

Na implementação, o objetivo é encontrar \(\widetilde w\) que minimize \(\|\widetilde X\widetilde w-y\|_2\). A forma matemática das equações normais é útil para a teoria, mas o cálculo explícito

\[ \left(\widetilde X^{\mathsf T}\widetilde X\right)^{-1} \widetilde X^{\mathsf T}y \]

não é a estratégia numérica recomendada.

Há duas razões principais. Primeiro, não precisamos da matriz inversa: precisamos apenas resolver um sistema para um vetor. Segundo, formar \(\widetilde X^{\mathsf T}\widetilde X\) eleva ao quadrado, aproximadamente, o número de condição da matriz, ampliando erros de arredondamento.

5.3.25.0.1 Implementação recomendada com NumPy

numpy.linalg.lstsq resolve diretamente o problema de mínimos quadrados, normalmente por métodos baseados em SVD. Ele aceita matrizes retangulares e também funciona quando as colunas não são independentes.

from dataclasses import dataclass

import numpy as np


@dataclass
class ModeloLinear:
    coeficientes: np.ndarray
    intercepto: float
    posto: int
    valores_singulares: np.ndarray


def ajustar_regressao_linear(X, y):
    X = np.asarray(X, dtype=float)
    y = np.asarray(y, dtype=float)

    if X.ndim != 2:
        raise ValueError("X deve ter forma (n_exemplos, n_atributos)")
    if y.ndim != 1 or len(y) != len(X):
        raise ValueError("y deve ter um valor para cada linha de X")
    if not np.all(np.isfinite(X)) or not np.all(np.isfinite(y)):
        raise ValueError("X e y devem conter somente valores finitos")

    X_tilde = np.column_stack([np.ones(len(X)), X])
    w_tilde, _, posto, singulares = np.linalg.lstsq(
        X_tilde, y, rcond=None
    )

    return ModeloLinear(
        coeficientes=w_tilde[1:],
        intercepto=float(w_tilde[0]),
        posto=int(posto),
        valores_singulares=singulares,
    )


def prever_regressao(modelo, X):
    X = np.asarray(X, dtype=float)
    return X @ modelo.coeficientes + modelo.intercepto

O segundo valor devolvido por lstsq contém somas de resíduos apenas em certas configurações de forma e posto; por isso, é mais claro calcular as métricas explicitamente a partir das previsões.

def metricas_regressao(y, y_predito):
    y = np.asarray(y, dtype=float)
    y_predito = np.asarray(y_predito, dtype=float)
    residuos = y - y_predito

    mse = np.mean(residuos**2)
    rmse = np.sqrt(mse)
    mae = np.mean(np.abs(residuos))

    denominador = np.sum((y - np.mean(y))**2)
    r2 = np.nan if denominador == 0 else (
        1 - np.sum(residuos**2) / denominador
    )
    return {"mse": mse, "rmse": rmse, "mae": mae, "r2": r2}

Quando todos os alvos são iguais, o denominador de \(R^2\) é zero; retornar NaN torna explícito que a métrica não está definida nessa amostra.

5.3.25.0.2 Exemplo completo
X_treino = np.array([
    [50.0, 0.10],
    [90.0, 0.25],
    [140.0, 0.40],
    [200.0, 0.65],
    [280.0, 0.80],
])
y_treino = np.array([1.1, 1.8, 2.9, 4.1, 5.4])

modelo = ajustar_regressao_linear(X_treino, y_treino)
predicoes = prever_regressao(modelo, X_treino)

print("intercepto:", modelo.intercepto)
print("coeficientes:", modelo.coeficientes)
print("posto:", modelo.posto)
print(metricas_regressao(y_treino, predicoes))

Com dois atributos e intercepto, esperamos posto \(3\). Um valor menor indica dependência linear detectada numericamente. Isso não torna as previsões automaticamente inúteis, mas impede interpretar os coeficientes como uma solução única.

5.3.25.0.3 Entendendo a fatoração QR

Se \(\widetilde X\) tem posto completo de colunas e sua QR reduzida é

\[ \widetilde X=QR, \]

então

\[ Q\in\mathbb R^{N\times p}, \qquad R\in\mathbb R^{p\times p}, \qquad Q^{\mathsf T}Q=I_p, \]

com \(p=d+1\) e \(R\) triangular superior. Substituindo na condição de mínimos quadrados, a solução satisfaz

\[ R\widetilde w=Q^{\mathsf T}y. \tag{5.29}\]

Resolvemos Equation 5.29 por substituição retroativa, sem calcular \(R^{-1}\). Em NumPy:

Q, R = np.linalg.qr(X_tilde, mode="reduced")
w_tilde = np.linalg.solve(R, Q.T @ y)

A QR é mais estável que resolver equações normais e costuma ser uma boa opção para matrizes densas com posto completo. Bibliotecas maduras usam transformações de Householder ou técnicas equivalentes; implementar Gram–Schmidt clássico como solucionador de produção é desaconselhável por sua sensibilidade a arredondamentos.

5.3.25.0.4 SVD, pseudoinversa e posto

A decomposição em valores singulares escreve

\[ \widetilde X=U\Sigma V^{\mathsf T}. \]

Valores singulares muito pequenos revelam direções quase redundantes. A pseudoinversa é

\[ \widetilde X^+ =V\Sigma^+U^{\mathsf T}, \]

onde \(\Sigma^+\) inverte apenas os valores singulares tratados como não nulos. Então,

\[ \widetilde w^*=\widetilde X^+y. \]

A tolerância usada para considerar um valor singular nulo é uma decisão numérica. O argumento rcond de lstsq controla essa decisão; None usa o padrão apropriado da biblioteca.

5.3.25.0.5 Condicionamento

O número de condição em norma 2 é, para posto completo,

\[ \kappa_2(\widetilde X) =\frac{\sigma_{\max}}{\sigma_{\min}}. \]

Quanto maior \(\kappa_2\), mais sensível a solução fica a pequenas perturbações. Podemos estimá-lo por

condicao = np.linalg.cond(X_tilde)
print("número de condição:", condicao)

Um valor elevado não possui um limiar universal de “falha”; sua gravidade depende da precisão numérica e da aplicação. Padronização pode reduzir diferenças de escala, mas não remove redundância estrutural. Regularização, como regressão ridge, pode estabilizar coeficientes ao aceitar um pequeno viés.

5.3.25.0.6 Qual método escolher?
Situação Estratégia típica
matriz densa moderada lstsq ou QR
posto deficiente ou quase deficiente SVD/pseudoinversa
muitos exemplos e poucos atributos QR ou solucionador especializado
dados muito grandes ou em fluxo gradiente estocástico ou métodos iterativos
matriz esparsa rotinas próprias para matrizes esparsas
necessidade de estabilização regularização ridge
5.3.25.0.7 Treino, validação e teste

Ajuste os coeficientes somente no treino. Use validação para escolher transformações, regularização ou outros hiperparâmetros e teste para a avaliação final. Se houver padronização, ajuste média e desvio no treino e reutilize esses valores nos demais conjuntos.

WarningEvite inv(X.T @ X) @ X.T @ y

Além de falhar em posto deficiente, essa expressão forma uma matriz com condicionamento pior e calcula uma inversa desnecessária. Prefira np.linalg.lstsq(X, y, rcond=None) ou um solucionador adequado à estrutura dos dados.

5.3.25.1 Verificações após o ajuste

  1. Compare o posto devolvido com o número de parâmetros.
  2. Examine valores singulares e número de condição.
  3. Verifique resíduos e métricas em treino e validação.
  4. Inspecione padrões dos resíduos em função das previsões e atributos.
  5. Confirme que o mesmo pré-processamento será aplicado em produção.

5.3.26 Resumo

A regressão linear aprende uma função de saída real

\[ h_{w,b}(x)=w^{\mathsf T}x+b \]

minimizando a média dos quadrados dos resíduos. Embora o modelo seja simples, seu estudo reuniu representação matricial, projeção ortogonal, cálculo multivariável e estabilidade numérica.

5.3.26.1 Mapa conceitual

Elemento Expressão
matriz de projeto \(\widetilde X\in\mathbb R^{N\times(d+1)}\)
parâmetros \(\widetilde w=(b,w_1,\ldots,w_d)^{\mathsf T}\)
previsões \(\widehat y=\widetilde X\widetilde w\)
resíduos \(e=y-\widehat y\)
objetivo \(\|e\|_2^2/N\)
gradiente \(2\widetilde X^{\mathsf T}(\widetilde X\widetilde w-y)/N\)
condição ótima \(\widetilde X^{\mathsf T}e=0\)
equações normais \(\widetilde X^{\mathsf T}\widetilde X\widetilde w=\widetilde X^{\mathsf T}y\)
solução geral de menor norma \(\widetilde w^*=\widetilde X^+y\)

A condição \(\widetilde X^{\mathsf T}e=0\) possui duas leituras equivalentes:

  • geometria: a previsão é a projeção de \(y\) no espaço coluna e o resíduo é perpendicular a esse espaço;
  • cálculo: o gradiente do MSE é zero no mínimo.

5.3.26.2 Fluxo recomendado de implementação

  1. Separe treino, validação e teste.
  2. Ajuste transformações de atributos somente no treino.
  3. Adicione o intercepto ou configure a biblioteca para estimá-lo.
  4. Resolva mínimos quadrados com lstsq, QR, SVD ou método apropriado à estrutura dos dados.
  5. Examine posto, valores singulares e condicionamento.
  6. Calcule MSE ou RMSE e métricas complementares em dados não usados no ajuste.
  7. Analise resíduos e verifique padrões, valores atípicos e mudança de distribuição.
ImportantA solução não é apenas uma fórmula

Calcular explicitamente \((\widetilde X^{\mathsf T}\widetilde X)^{-1}\) é desnecessário e pode ser instável. A pseudoinversa é um conceito matemático; em código, use um solucionador numérico confiável.

5.3.26.3 O que cada métrica responde

  • MSE: qual é a perda quadrática média?
  • RMSE: qual é a escala típica do erro com penalização quadrática, nas unidades do alvo?
  • MAE: qual é o módulo médio do erro com influência linear?
  • \(R^2\): quanto o modelo melhora em relação ao preditor constante da média naquele conjunto?

Resultados de treino respondem sobre ajuste; resultados de validação e teste fornecem evidência de generalização. Nenhuma dessas métricas, por si só, estabelece causalidade ou segurança da aplicação.

5.3.26.4 Erros comuns

  • esquecer a coluna de intercepto;
  • transpor a matriz de projeto e trocar exemplos por atributos;
  • usar a fórmula da inversa sem verificar posto;
  • interpretar coeficientes sem considerar unidades e correlação entre atributos;
  • calcular pré-processamento com dados de teste;
  • extrapolar muito além da região observada;
  • relatar somente \(R^2\) e ocultar a escala dos resíduos.

5.3.26.5 Questões conceituais

  1. Por que SSE e MSE possuem o mesmo minimizador?
  2. Por que o resíduo ótimo é ortogonal às colunas da matriz de projeto?
  3. Ter mais exemplos que parâmetros garante solução única? Justifique.
  4. Por que formar \(X^{\mathsf T}X\) pode piorar o condicionamento?
  5. Em que sentido uma regressão com atributo \(x^2\) ainda é linear?
  6. Como um modelo pode apresentar \(R^2\) negativo no conjunto de teste?

5.3.26.6 Exercícios

  1. Para \(\widetilde X=\begin{bmatrix}1&0\\1&1\\1&2\end{bmatrix}\) e \(y=(1,2,2)^{\mathsf T}\), verifique por multiplicação as equações normais usando \(\widetilde w=(7/6,1/2)^{\mathsf T}\).
  2. Construa uma matriz de projeto com duas colunas idênticas. Calcule seu posto e explique por que os coeficientes não são únicos.
  3. Compare np.linalg.lstsq com a solução explícita das equações normais em uma matriz cujas colunas sejam quase colineares.
  4. Ajuste uma reta a uma amostra, adicione um valor-alvo extremamente distante e observe como coeficientes, RMSE e MAE mudam.
  5. Examine um gráfico de resíduos contra previsões. Que padrão sugeriria que uma relação não linear permanece sem modelagem?

5.3.26.7 Critério de domínio

Ao concluir esta seção, o estudante deve ser capaz de:

  • montar \(\widetilde X\), \(y\), \(\widehat y\) e \(e\) com dimensões corretas;
  • derivar as equações normais por projeção e pelo gradiente;
  • explicar posto, pseudoinversa e unicidade;
  • escolher uma rotina numérica apropriada sem calcular uma inversa explícita;
  • avaliar o modelo fora da amostra e interpretar seus resíduos.

5.3.27 Animação

Uma animação pode mostrar simultaneamente duas visões do mesmo processo:

  • no espaço dos dados, a reta muda à medida que \(b\) e \(w\) são atualizados;
  • no espaço dos parâmetros, o ponto \((b,w)\) percorre a superfície do MSE em direção ao mínimo.

Para uma regressão com um atributo, o MSE é uma função quadrática de dois parâmetros. Suas curvas de nível são elipses quando a solução é única.

O gradiente descendente atravessa curvas de nível do MSE em direção ao mínimo.

Elipses muito alongadas indicam escalas diferentes ou forte correlação entre as direções dos parâmetros. Nesse cenário, uma taxa de aprendizado alta pode fazer a trajetória oscilar de um lado para outro do vale.

5.3.27.1 Registrando a trajetória

O código a seguir ajusta uma reta por gradiente descendente e guarda uma cópia dos parâmetros a cada passo.

import numpy as np


def trajetoria_gradiente(X, y, taxa=0.05, passos=100):
    X = np.asarray(X, dtype=float).reshape(-1)
    y = np.asarray(y, dtype=float)
    b, w = 0.0, 0.0
    historico = []

    for passo in range(passos + 1):
        predicoes = b + w * X
        residuos = predicoes - y
        mse = np.mean(residuos**2)
        historico.append((passo, b, w, mse))

        grad_b = 2 * np.mean(residuos)
        grad_w = 2 * np.mean(residuos * X)
        b -= taxa * grad_b
        w -= taxa * grad_w

    return historico

Usamos residuos = predicoes - y, por isso o gradiente aparece com sinal positivo antes da subtração. Se definíssemos resíduos como \(y-\widehat y\), o sinal da fórmula intermediária mudaria, mas a atualização final seria equivalente.

5.3.27.2 Animando a reta

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation


def animar_ajuste_linear(X, y, taxa=0.05, passos=100):
    X = np.asarray(X, dtype=float).reshape(-1)
    y = np.asarray(y, dtype=float)
    historico = trajetoria_gradiente(X, y, taxa, passos)

    fig, (ax_dados, ax_erro) = plt.subplots(1, 2, figsize=(10, 4))
    ax_dados.scatter(X, y, label="observações")
    eixo_x = np.linspace(X.min(), X.max(), 100)
    reta, = ax_dados.plot([], [], label="modelo")
    ax_dados.set_xlim(X.min(), X.max())
    margem_y = 0.1 * max(np.ptp(y), 1.0)
    ax_dados.set_ylim(y.min() - margem_y, y.max() + margem_y)
    ax_dados.legend()

    passos_hist = [estado[0] for estado in historico]
    erros_hist = [estado[3] for estado in historico]
    ax_erro.plot(passos_hist, erros_hist, color="lightgray")
    ponto_erro, = ax_erro.plot([], [], "o")
    ax_erro.set_xlabel("passo")
    ax_erro.set_ylabel("MSE")
    titulo = fig.suptitle("")

    def atualizar(estado):
        passo, b, w, mse = estado
        reta.set_data(eixo_x, b + w * eixo_x)
        ponto_erro.set_data([passo], [mse])
        titulo.set_text(
            f"passo={passo} · b={b:.3f} · w={w:.3f} · MSE={mse:.4f}"
        )
        return reta, ponto_erro, titulo

    animacao = FuncAnimation(
        fig,
        atualizar,
        frames=historico,
        interval=100,
        repeat=False,
    )
    return fig, animacao

Em um notebook:

from IPython.display import HTML

X = np.array([0.0, 1.0, 2.0, 3.0, 4.0])
y = np.array([1.1, 2.8, 5.2, 6.9, 9.2])

fig, animacao = animar_ajuste_linear(
    X, y, taxa=0.03, passos=100
)
plt.close(fig)
HTML(animacao.to_jshtml())

5.3.27.3 Experimentos guiados

  1. Aumente a taxa de aprendizado gradualmente. Em que valor o MSE deixa de diminuir de modo estável?
  2. Multiplique \(X\) por \(1\,000\) sem alterar a taxa. Explique a mudança usando a expressão do gradiente.
  3. Padronize \(X\) e repita o experimento. Compare a trajetória.
  4. Adicione um valor atípico a \(y\). Observe como a reta ótima muda.
  5. Compare os parâmetros finais ao resultado de np.linalg.lstsq.
NoteA solução direta não percorre a animação

QR ou SVD calcula a solução por operações de álgebra linear e não gera naturalmente uma sequência de retas intermediárias. A trajetória acima pertence ao gradiente descendente, um algoritmo alternativo para o mesmo objetivo quadrático.

5.4 Regressão Logística

A regressão logística é um modelo de classificação probabilística binária. Embora o nome contenha “regressão”, o alvo observado pertence a duas classes. Usaremos a codificação

\[ y\in\{0,1\}, \]

em que \(y=1\) representa o evento de interesse e \(y=0\), seu complemento. Exemplos incluem inadimplência ou pagamento, fraude ou transação legítima, falha ou funcionamento e presença ou ausência de uma condição clínica.

O objetivo não é apenas devolver uma classe. Queremos modelar

\[ p(x)=P(Y=1\mid X=x), \]

a probabilidade condicional do evento positivo dados os atributos. Como as classes são complementares,

\[ P(Y=0\mid X=x)=1-p(x). \]

5.4.1 Por que a regressão linear não basta?

Poderíamos codificar os rótulos como zero e um e ajustar \(w^{\mathsf T}x+b\) por mínimos quadrados. Esse procedimento, chamado modelo de probabilidade linear, possui limitações importantes:

  • a saída pode ser menor que zero ou maior que um;
  • o efeito de uma variação na pontuação permanece constante, mesmo próximo aos extremos probabilísticos;
  • a variância de uma variável binária depende de sua probabilidade;
  • o MSE não corresponde diretamente à verossimilhança de uma observação Bernoulli.

A regressão logística mantém a pontuação linear

\[ z=w^{\mathsf T}x+b, \]

mas aplica uma transformação que leva qualquer número real ao intervalo \((0,1)\):

\[ p(x)=\sigma(z)=\frac{1}{1+e^{-z}}. \tag{5.30}\]

A regressão logística separa a estimativa de probabilidade da decisão tomada com um limiar.

5.4.2 Probabilidade não é decisão

Depois de estimar \(p(x)\), uma aplicação pode convertê-la em classe usando um limiar \(\tau\):

\[ \widehat y= \begin{cases} 1,&p(x)\geq\tau,\\ 0,&p(x)<\tau. \end{cases} \]

O valor \(\tau=0{,}5\) é comum, mas não obrigatório. Se deixar de detectar uma fraude custa muito mais que investigar um alarme falso, um limiar menor pode ser adequado. O modelo estima probabilidades; a política de decisão combina essas probabilidades com custos e restrições.

Como \(\sigma(0)=0{,}5\) e a sigmoide é crescente, o limiar \(0{,}5\) produz a fronteira

\[ w^{\mathsf T}x+b=0, \]

a mesma forma geométrica do Perceptron. A diferença está na saída e no treinamento: o Perceptron fornece um sinal e usa correções de erros; a regressão logística fornece um valor contínuo e otimiza uma perda probabilística.

5.4.3 Interpretação condicional

Não existe, para cada entrada \(x\), um rótulo determinístico que o modelo precise descobrir. Duas observações com atributos iguais podem ter resultados diferentes. A incerteza é representada por uma distribuição Bernoulli:

\[ Y\mid X=x\sim\operatorname{Bernoulli}(p(x)). \]

Isso significa

\[ P(Y=y\mid X=x) =p(x)^y[1-p(x)]^{1-y}, \qquad y\in\{0,1\}. \]

Ao observar muitos casos semelhantes com \(p(x)=0{,}8\), esperamos uma proporção próxima de \(80\%\) de resultados positivos, não a certeza de que cada caso será positivo.

5.4.4 Exemplo de leitura

Considere um modelo de falha de servidores:

\[ z=-4+0{,}03\,\text{temperatura} +1{,}2\,\text{carga}. \]

Para temperatura \(80\) e carga \(0{,}75\),

\[ z=-4+0{,}03(80)+1{,}2(0{,}75)=-0{,}7, \]

e

\[ p=\sigma(-0{,}7)\approx0{,}332. \]

Esse número é uma estimativa condicional ao vetor de atributos e ao modelo ajustado. Não é uma frequência observada diretamente para aquele servidor individual.

5.4.5 Três níveis que não devem ser confundidos

Quantidade Domínio Significado
pontuação \(z\) \(\mathbb R\) evidência linear antes da transformação
probabilidade \(p=\sigma(z)\) \((0,1)\) estimativa de \(P(Y=1\mid X=x)\)
decisão \(\widehat y\) \(\{0,1\}\) ação após aplicar um limiar

Uma boa acurácia não garante probabilidades confiáveis. Se previsões de \(0{,}8\) correspondem a resultados positivos em apenas \(60\%\) dos casos, o modelo está mal calibrado, ainda que muitas classes estejam corretas. Calibração e discriminação são propriedades diferentes.

WarningProbabilidade do modelo não é certeza científica

A saída depende dos dados, atributos, população e suposições do modelo. Mudança de distribuição, grupos pouco representados e variáveis omitidas podem tornar probabilidades inadequadas. Em aplicações de alto impacto, avalie calibração e erros por subgrupo e defina supervisão humana.

5.4.6 Roteiro da seção

Nas próximas subseções, estudaremos:

  1. a função logística e sua relação com chances e log-odds;
  2. a classe de hipóteses probabilísticas;
  3. a perda de entropia cruzada derivada da Bernoulli;
  4. gradiente, Hessiana e métodos de otimização;
  5. implementação numericamente estável e avaliação.

5.4.7 Função Logística

Precisamos transformar uma pontuação \(z\in\mathbb R\) em uma probabilidade. A função logística, também chamada sigmoide, é

\[ \sigma(z) =\frac{1}{1+e^{-z}} =\frac{e^z}{1+e^z}. \tag{5.31}\]

Seu domínio é toda a reta real e sua imagem é o intervalo aberto \((0,1)\). Ela nunca produz exatamente zero ou um para um argumento real finito, mas se aproxima desses valores quando \(z\) tende a \(-\infty\) ou \(+\infty\).

A sigmoide converte uma pontuação real em probabilidade e satura próximo aos extremos.
5.4.7.0.1 Propriedades fundamentais

A sigmoide satisfaz

\[ \sigma(0)=\frac12, \qquad \sigma(-z)=1-\sigma(z). \]

Ela é estritamente crescente. Sua derivada possui uma forma especialmente conveniente:

\[ \begin{aligned} \sigma'(z) &=\frac{e^{-z}}{(1+e^{-z})^2}\\ &=\sigma(z)[1-\sigma(z)]. \end{aligned} \tag{5.32}\]

Como \(0<\sigma(z)<1\), a derivada é positiva. Seu valor máximo é \(1/4\), atingido em \(z=0\). Nas caudas, a derivada se aproxima de zero: dizemos que a função satura.

Para pequenas variações \(\Delta z\) próximas de zero,

\[ \Delta p\approx\sigma'(0)\Delta z=\frac14\Delta z. \]

Longe do centro, a mesma variação de pontuação causa uma alteração menor na probabilidade.

5.4.7.0.2 Chances e chances logarítmicas

Se um evento tem probabilidade \(p\), suas chances (odds) são

\[ \operatorname{odds}(p)=\frac{p}{1-p}. \]

Probabilidade \(p=0{,}8\), por exemplo, corresponde a chances \(0{,}8/0{,}2=4\): lemos “quatro para um” a favor do evento. Probabilidade \(0{,}5\) corresponde a chances \(1\).

O logaritmo das chances é a função logit:

\[ \operatorname{logit}(p) =\ln\left(\frac{p}{1-p}\right). \tag{5.33}\]

Aplicando-a à sigmoide,

\[ \frac{\sigma(z)}{1-\sigma(z)}=e^z \quad\Longrightarrow\quad \operatorname{logit}(\sigma(z))=z. \]

Portanto, sigmoide e logit são funções inversas:

\[ p=\sigma(z) \quad\Longleftrightarrow\quad z=\ln\left(\frac{p}{1-p}\right). \]

Na regressão logística, a quantidade linear não é a probabilidade, mas o logaritmo das chances:

\[ \ln\left(\frac{p(x)}{1-p(x)}\right) =w^{\mathsf T}x+b. \tag{5.34}\]

5.4.7.0.3 Interpretação de um coeficiente

Mantendo os outros atributos fixos, aumentar \(x_j\) em uma unidade soma \(w_j\) aos log-odds. Exponenciando, as chances são multiplicadas por \(e^{w_j}\):

\[ \frac{\operatorname{odds}(x_j+1)} {\operatorname{odds}(x_j)}=e^{w_j}. \]

Se \(w_j=\ln2\), uma unidade adicional duplica as chances. Isso não significa dobrar a probabilidade. Se ela passa de \(0{,}2\) para chances \(0{,}25\), dobrar as chances produz \(0{,}5\), que corresponde a probabilidade \(1/3\), não \(0{,}4\).

5.4.7.0.4 Relação com a distribuição Bernoulli

Uma variável Bernoulli com parâmetro \(p\) satisfaz

\[ P(Y=y\mid p)=p^y(1-p)^{1-y}, \qquad y\in\{0,1\}. \]

Defina o parâmetro natural

\[ \eta=\ln\left(\frac{p}{1-p}\right). \]

Como \(p=\sigma(\eta)\), podemos reescrever a massa de probabilidade:

\[ P(Y=y\mid\eta) =\exp\left[y\eta-\ln(1+e^\eta)\right]. \tag{5.35}\]

Essa é a forma de família exponencial da Bernoulli. A regressão logística modela o parâmetro natural por \(\eta=w^{\mathsf T}x+b\). Essa ligação explica por que a função logística e a perda de entropia cruzada aparecem juntas; elas não são apenas escolhas gráficas convenientes.

5.4.7.0.5 Função logística, probit e tangente hiperbólica

O modelo probit substitui a sigmoide pela função de distribuição acumulada normal \(\Phi(z)\). Ambas produzem curvas em S e frequentemente geram ajustes semelhantes após uma mudança de escala, mas correspondem a funções de ligação diferentes.

A tangente hiperbólica satisfaz

\[ \tanh(z)=2\sigma(2z)-1 \]

e possui imagem \((-1,1)\). Ela é comum como função de ativação em redes neurais, mas não representa diretamente uma probabilidade Bernoulli sem transformação adicional.

NoteLogístico não é logarítmico

O nome “regressão logística” vem da função logística. O logaritmo aparece porque o modelo torna os log-odds lineares nos atributos.

5.4.7.0.6 Intercepto e probabilidade de referência

No vetor homogêneo,

\[ \widetilde x=(1,x_1,\ldots,x_d), \qquad \widetilde w=(b,w_1,\ldots,w_d), \]

temos \(z=\widetilde w^{\mathsf T}\widetilde x\). Quando todos os atributos originais valem zero,

\[ p_0=\sigma(b), \]

de modo que \(b\) representa os log-odds de referência. Centralizar os atributos pode tornar essa referência mais interpretável.

5.4.7.0.7 Computação numericamente estável

A fórmula direta pode causar transbordamento ao calcular \(e^{-z}\) para \(z\) muito negativo. Uma implementação por ramos evita exponenciais gigantes:

import numpy as np


def sigmoide_estavel(z):
    z = np.asarray(z, dtype=float)
    saida = np.empty_like(z)
    positivos = z >= 0

    saida[positivos] = 1 / (1 + np.exp(-z[positivos]))
    exp_z = np.exp(z[~positivos])
    saida[~positivos] = exp_z / (1 + exp_z)
    return saida

Para perdas logísticas, bibliotecas usam identidades como logaddexp e logsumexp, evitando calcular primeiro probabilidades arredondadas a zero ou um.

5.4.7.1 Exercícios

  1. Demonstre a identidade Equation 5.32.
  2. Converta probabilidades \(0{,}1\), \(0{,}5\) e \(0{,}9\) em chances e log-odds.
  3. Se \(w_j=0{,}4\), por qual fator as chances mudam quando \(x_j\) aumenta três unidades?
  4. Mostre algebricamente que a inversa da função logit é a sigmoide.
  5. Explique por que uma alteração fixa nos log-odds não corresponde a uma alteração fixa na probabilidade.

5.4.8 Hipóteses

A classe de hipóteses da regressão logística é

\[ \mathcal H_{\mathrm{log}} =\left\{ h_{w,b}(x)=\sigma(w^{\mathsf T}x+b) :w\in\mathbb R^d,\ b\in\mathbb R \right\}. \tag{5.36}\]

Cada hipótese associa a uma entrada uma probabilidade estimada:

\[ h_{w,b}(x) =\widehat P(Y=1\mid X=x). \]

Como \(Y\) é binária,

\[ \widehat P(Y=0\mid X=x)=1-h_{w,b}(x). \]

Essa função é uma probabilidade condicional, não uma densidade de variável contínua. Para \(Y\in\{0,1\}\), usamos uma função massa de probabilidade Bernoulli:

\[ \widehat P(Y=y\mid X=x) =h(x)^y[1-h(x)]^{1-y}. \tag{5.37}\]

5.4.9 Representação homogênea e matricial

Com

\[ \widetilde x=(1,x_1,\ldots,x_d), \qquad \widetilde w=(b,w_1,\ldots,w_d), \]

escrevemos

\[ h_{\widetilde w}(x) =\sigma(\widetilde w^{\mathsf T}\widetilde x). \]

Para uma amostra inteira,

\[ z=\widetilde X\widetilde w, \qquad \widehat p=\sigma(z), \tag{5.38}\]

em que a sigmoide é aplicada componente a componente. Assim, \(z,\widehat p\in\mathbb R^N\): há uma pontuação e uma probabilidade para cada exemplo.

5.4.10 Codificação dos rótulos

A codificação \(\{0,1\}\) é conveniente para a Bernoulli e a entropia cruzada. Se os dados usam \(\{-1,+1\}\), podemos converter por

\[ y_{01}=\frac{y_{\pm1}+1}{2}, \qquad y_{\pm1}=2y_{01}-1. \]

As duas convenções são válidas, mas suas fórmulas de perda diferem. Misturá-las silenciosamente é uma fonte comum de erros de sinal.

5.4.11 Superfícies de probabilidade

Todos os pontos com a mesma probabilidade \(c\in(0,1)\) satisfazem

\[ \sigma(w^{\mathsf T}x+b)=c. \]

Aplicando a função logit,

\[ w^{\mathsf T}x+b =\ln\left(\frac{c}{1-c}\right). \]

Portanto, as superfícies de probabilidade constante são hiperplanos paralelos. Para \(c=0{,}5\), o lado direito é zero e obtemos a fronteira

\[ w^{\mathsf T}x+b=0. \]

Para um limiar geral \(\tau\), a fronteira de decisão é

\[ w^{\mathsf T}x+b =\operatorname{logit}(\tau). \tag{5.39}\]

Mudar o limiar desloca a fronteira paralelamente; não é necessário treinar novamente o modelo apenas para testar outra política de decisão.

5.4.12 Interpretação dos parâmetros

O modelo supõe linearidade nos log-odds:

\[ \operatorname{logit}(h(x)) =b+w_1x_1+\cdots+w_dx_d. \]

Cada \(w_j\) representa a mudança nos log-odds para uma unidade adicional de \(x_j\), mantendo os outros atributos constantes. O fator \(e^{w_j}\) é a razão de chances correspondente.

Essa interpretação depende da especificação do modelo. Se uma relação é curva, omitir termos não lineares pode tornar o coeficiente enganoso. Se dois atributos são fortemente correlacionados, a frase “mantendo os outros constantes” pode descrever uma comparação rara ou impossível nos dados.

5.4.13 Engenharia de atributos

Assim como na regressão linear, podemos usar um mapa de características:

\[ h_w(x)=\sigma\!\left(w^{\mathsf T}\phi(x)\right). \]

Com \(\phi(x)=(1,x_1,x_2,x_1x_2,x_1^2)\), a fronteira no espaço original pode ser curva, embora os log-odds continuem lineares nos parâmetros. Isso aumenta a capacidade e deve ser acompanhado por validação e, muitas vezes, regularização.

5.4.14 O que a hipótese assume — e o que não assume

A regressão logística não exige que os atributos sigam distribuição normal. A especificação central é que os log-odds condicionais sejam modelados pela combinação escolhida de características. Para inferência estatística tradicional, outras condições podem ser necessárias; para predição, avaliamos sobretudo desempenho, calibração e estabilidade fora da amostra.

WarningSeparação perfeita

Se uma combinação linear separa perfeitamente as classes, a verossimilhança sem regularização pode continuar melhorando enquanto a norma dos coeficientes tende ao infinito. As probabilidades ficam extremas e não há estimativa finita usual de máxima verossimilhança. Regularização ou métodos específicos tratam esse caso.

5.4.15 Exemplo vetorizado

import numpy as np

X = np.array([
    [70.0, 0.40],
    [85.0, 0.75],
    [60.0, 0.25],
])
w = np.array([0.03, 1.20])
b = -4.0

z = X @ w + b
p = 1 / (1 + np.exp(-z))
classes = (p >= 0.5).astype(int)

print("pontuações:", z)
print("probabilidades:", p)
print("classes:", classes)

O vetor p é a saída probabilística da hipótese; classes depende do limiar escolhido e pertence à camada de decisão.

5.4.15.1 Questões

  1. Derive Equation 5.39 para \(\tau=0{,}8\).
  2. Converta uma base rotulada em \(\{-1,+1\}\) para \(\{0,1\}\).
  3. Explique por que todas as superfícies de probabilidade constante são paralelas no modelo sem transformações não lineares.
  4. Dê um mapa \(\phi(x)\) que permita uma fronteira circular em duas dimensões.

5.4.16 Erro

A amostra não contém as probabilidades verdadeiras; contém realizações binárias. Para relacionar essas observações aos parâmetros, usamos o modelo Bernoulli e o princípio da máxima verossimilhança.

Se

\[ p_n=\sigma(\widetilde x_n^{\mathsf T}\widetilde w), \]

a probabilidade atribuída ao rótulo \(y_n\in\{0,1\}\) é

\[ P(Y_n=y_n\mid x_n,\widetilde w) =p_n^{y_n}(1-p_n)^{1-y_n}. \]

Assumindo que as observações são condicionalmente independentes dados os atributos, a verossimilhança da amostra é

\[ L(\widetilde w) =\prod_{n=1}^{N} p_n^{y_n}(1-p_n)^{1-y_n}. \tag{5.40}\]

Essa expressão é uma função dos parâmetros para os dados fixados. Ela não é a probabilidade de que os parâmetros sejam verdadeiros.

5.4.16.0.1 Do produto à soma

Produtos de muitas probabilidades pequenas podem sofrer subfluxo numérico. Como o logaritmo é crescente, maximizar \(L\) equivale a maximizar a log-verossimilhança:

\[ \ell(\widetilde w) =\ln L(\widetilde w) =\sum_{n=1}^{N} \left[ y_n\ln p_n+(1-y_n)\ln(1-p_n) \right]. \]

Algoritmos de aprendizado costumam minimizar uma perda. Tomamos a média negativa:

\[ E_{\mathrm{in}}(\widetilde w) =-\frac1N\sum_{n=1}^{N} \left[ y_n\ln p_n+(1-y_n)\ln(1-p_n) \right]. \tag{5.41}\]

Essa função é chamada entropia cruzada binária, log-loss ou perda logística.

A entropia cruzada penaliza fortemente probabilidades confiantes atribuídas à classe errada.

Para \(y=1\), a perda individual é \(-\ln p\); para \(y=0\), é \(-\ln(1-p)\). Uma previsão correta e confiante recebe perda próxima de zero. Uma previsão errada e confiante recebe perda muito grande.

5.4.16.0.2 Forma com rótulos \(\{-1,+1\}\)

Se usarmos \(t_n\in\{-1,+1\}\) e a pontuação \(z_n=\widetilde x_n^{\mathsf T}\widetilde w\), a probabilidade do rótulo observado é

\[ P(T_n=t_n\mid x_n)=\sigma(t_nz_n). \]

Logo, a perda individual é

\[ -\ln\sigma(t_nz_n) =\ln\left(1+e^{-t_nz_n}\right). \]

O erro médio torna-se

\[ E_{\mathrm{in}}(\widetilde w) =\frac1N\sum_{n=1}^{N} \ln\left(1+e^{-t_n \widetilde x_n^{\mathsf T}\widetilde w} \right). \tag{5.42}\]

As formas Equation 5.41 e Equation 5.42 são equivalentes após converter os rótulos. A expressão \(\ln(1+e^a)\) é chamada softplus.

5.4.16.0.3 Relação com a margem

Na codificação \(\{-1,+1\}\), a margem é

\[ m_n=t_nz_n. \]

A perda \(\ln(1+e^{-m_n})\) é decrescente na margem:

  • margem grande e positiva: classificação correta e perda próxima de zero;
  • margem zero: probabilidade \(0{,}5\) e perda \(\ln2\);
  • margem negativa: classificação errada, com perda que cresce à medida que o erro se torna mais confiante.

Ao contrário da perda zero–um, a perda logística é suave e fornece um gradiente útil em quase todas as situações.

5.4.16.0.4 Por que não usar somente acurácia?

Acurácia considera apenas o lado do limiar. Duas previsões de \(0{,}51\) e \(0{,}99\) para um caso positivo são ambas corretas, mas a segunda atribui mais probabilidade ao resultado observado. A log-loss distingue essas situações e é uma regra de pontuação própria: em expectativa, é minimizada ao relatar a probabilidade verdadeira.

Isso não elimina a necessidade de métricas de decisão. Log-loss avalia qualidade probabilística; precisão, revocação e custos avaliam o que acontece depois de aplicar um limiar.

5.4.16.0.5 Computação estável

Calcular primeiro \(p=\sigma(z)\) e depois log(p) pode produzir log(0) por arredondamento. Com rótulos \(\{-1,+1\}\), use np.logaddexp(0, -t * z), que calcula a softplus de modo estável:

import numpy as np


def perda_logistica_pm1(X, t, w, b):
    z = X @ w + b
    perdas = np.logaddexp(0.0, -t * z)
    return np.mean(perdas)

Com rótulos \(\{0,1\}\), uma forma estável diretamente nos logits é

\[ \ell(z,y)=\ln(1+e^z)-yz. \]

def entropia_cruzada_logits(X, y, w, b):
    z = X @ w + b
    perdas = np.logaddexp(0.0, z) - y * z
    return np.mean(perdas)
5.4.16.0.6 Regularização

É comum adicionar uma penalidade aos pesos:

\[ E_\lambda(\widetilde w) =E_{\mathrm{in}}(\widetilde w) +\frac{\lambda}{2}\|w\|_2^2. \]

O intercepto normalmente não é penalizado. A regularização reduz coeficientes extremos, ajuda em separação perfeita e controla sobreajuste. O valor \(\lambda\) deve ser escolhido por validação, não pelo conjunto de teste.

WarningLog-loss não possui limite superior

Uma probabilidade quase zero para um evento que ocorre produz perda muito grande. Isso é intencional: o modelo é responsabilizado por confiança indevida. Também torna essencial investigar rótulos incorretos e usar operações numericamente estáveis.

5.4.16.1 Exemplo

Para um caso positivo com \(p=0{,}8\),

\[ -\ln(0{,}8)\approx0{,}223. \]

Se o modelo atribui \(p=0{,}01\) ao mesmo resultado,

\[ -\ln(0{,}01)\approx4{,}605. \]

A segunda previsão não é apenas incorreta segundo um limiar de \(0{,}5\); é incorreta com alta confiança.

5.4.16.2 Exercícios

  1. Derive Equation 5.41 a partir de
  2. Mostre que \(-\ln\sigma(a)=\ln(1+e^{-a})\).
  3. Calcule a log-loss para \(y=0\) e previsões \(p=0{,}1\) e \(p=0{,}9\).
  4. Explique por que maximizar a verossimilhança equivale a minimizar a log-verossimilhança negativa.
  5. Compare a perda logística e a perda zero–um em margens \(-2,0,2\).

5.4.17 Algoritmo

Treinar a regressão logística significa encontrar parâmetros que minimizem a entropia cruzada, ou, equivalentemente, maximizem a verossimilhança Bernoulli. Para rótulos \(y\in\{0,1\}\), o problema é

\[ \widetilde w^* \in\operatorname*{arg\,min}_{\widetilde w} \frac1N\sum_{n=1}^{N} \left[ \ln(1+e^{z_n})-y_nz_n \right], \qquad z=\widetilde X\widetilde w. \tag{5.43}\]

Na regressão linear, zerar o gradiente produziu um sistema linear com solução fechada. Aqui, as probabilidades \(p_n=\sigma(\widetilde x_n^{\mathsf T}\widetilde w)\) dependem não linearmente dos parâmetros. A condição de primeira ordem forma um sistema não linear e, em geral, precisa ser resolvida iterativamente.

5.4.17.1 Gradiente e Hessiana em uma visão antecipada

Reunindo as probabilidades no vetor \(p\), o gradiente é

\[ \nabla E(\widetilde w) =\frac1N\widetilde X^{\mathsf T}(p-y). \tag{5.44}\]

O gradiente aponta na direção de maior crescimento local. Para diminuir a perda, movemo-nos na direção oposta, \(-\nabla E\).

A Hessiana é

\[ \nabla^2E(\widetilde w) =\frac1N\widetilde X^{\mathsf T}S\widetilde X, \tag{5.45}\]

em que

\[ S=\operatorname{diag}\left(p_1(1-p_1),\ldots, p_N(1-p_N)\right). \]

Para qualquer vetor \(v\),

\[ v^{\mathsf T}\nabla^2E(\widetilde w)v =\frac1N (\widetilde Xv)^{\mathsf T}S(\widetilde Xv) \geq0, \]

pois os elementos diagonais de \(S\) são não negativos. Logo, a perda é convexa: não há mínimos locais ruins. Isso não significa que toda execução seja trivial; condicionamento, escolha do passo e separação perfeita ainda importam.

5.4.17.2 Três estratégias

As subseções seguintes apresentam métodos relacionados:

Método Informação usada Custo por iteração Característica
gradiente descendente primeira derivada geralmente \(O(Nd)\) simples e escalável
Newton/IRLS gradiente e Hessiana inclui sistema em \(d+1\) variáveis poucas iterações perto do mínimo
máximo declive com busca de passo gradiente e escolha adaptativa de \(\eta\) várias avaliações da perda reduz risco de passo inadequado

Em bases muito grandes, o gradiente pode ser estimado com minilotes. Em dimensão moderada, Newton ou métodos quase-Newton, como BFGS e L-BFGS, costumam convergir em menos iterações.

5.4.17.3 Regularização

Com penalidade \(L_2\), minimizamos

\[ E_\lambda(\widetilde w) =E(\widetilde w)+\frac{\lambda}{2}\|w\|_2^2, \]

normalmente excluindo o intercepto \(b\). O gradiente ganha o termo \(\lambda w\) e a Hessiana ganha \(\lambda I\) nas coordenadas penalizadas. Além de controlar sobreajuste, esse termo melhora o condicionamento e produz solução finita em muitos casos de separação perfeita.

5.4.17.4 Estrutura de uma iteração

Independentemente do método, um ciclo típico contém:

  1. calcular os logits \(z=\widetilde X\widetilde w\);
  2. calcular probabilidades ou quantidades equivalentes de modo estável;
  3. avaliar perda e gradiente;
  4. determinar uma direção \(d_t\);
  5. escolher um tamanho de passo \(\eta_t\);
  6. atualizar \(\widetilde w^{(t+1)}=\widetilde w^{(t)}+\eta_td_t\);
  7. verificar critérios de parada.

Para gradiente descendente, \(d_t=-\nabla E\). Para Newton,

\[ d_t=-[\nabla^2E(\widetilde w^{(t)})]^{-1} \nabla E(\widetilde w^{(t)}), \]

mas uma implementação resolve o sistema linear \(\nabla^2E\,d_t=-\nabla E\) sem calcular a inversa.

5.4.17.5 Critérios de parada

Um único critério pode ser enganoso. Implementações robustas combinam:

  • norma do gradiente abaixo de uma tolerância;
  • variação relativa da perda pequena;
  • variação relativa dos parâmetros pequena;
  • número máximo de iterações;
  • detecção de valores não finitos;
  • desempenho de validação para parada antecipada, quando apropriado.

A perda deve ser monitorada em precisão suficiente. Uma mudança absoluta de \(10^{-6}\) pode ser irrelevante para uma perda de \(10^6\) e importante para uma perda de \(10^{-8}\); por isso, tolerâncias relativas são úteis.

5.4.17.6 Inicialização e escala

Inicializar em zero é válido para uma regressão logística isolada: não há simetria entre várias unidades que precise ser quebrada. Se as classes são muito desbalanceadas, uma inicialização útil do intercepto é

\[ b^{(0)} =\ln\left(\frac{\overline y}{1-\overline y}\right), \]

com pesos inicialmente zero, desde que \(0<\overline y<1\). Isso começa com a prevalência da classe positiva.

Padronizar atributos melhora o condicionamento e torna uma única taxa de aprendizado mais razoável para todas as coordenadas. As estatísticas de padronização devem ser estimadas somente no treino.

WarningConvergência numérica não garante um bom modelo

Um otimizador pode minimizar perfeitamente a perda de treinamento e ainda generalizar mal, estar descalibrado ou apresentar desempenho desigual entre grupos. Otimização resolve os parâmetros do objetivo especificado; avaliação verifica se esse objetivo serve à aplicação.

5.4.17.7 Diagnósticos básicos

Durante o treinamento, registre pelo menos:

  • perda de treino e validação;
  • norma do gradiente;
  • norma dos parâmetros;
  • tamanho do passo;
  • número de iterações e motivo da parada.

Crescimento contínuo da norma dos parâmetros com perda decrescente pode indicar separação perfeita sem regularização. Perda NaN ou infinita costuma indicar operações instáveis ou passo excessivo.

5.4.17.8 Gradiente

Para uma função escalar \(f:\mathbb R^p\to\mathbb R\), o gradiente reúne as derivadas parciais:

\[ \nabla f(w)= \begin{bmatrix} \partial f/\partial w_1\\ \vdots\\ \partial f/\partial w_p \end{bmatrix}. \]

Adotaremos gradientes como vetores coluna. A derivada direcional na direção unitária \(v\) é

\[ D_vf(w)=\nabla f(w)^{\mathsf T}v. \]

Por Cauchy–Schwarz, esse valor é máximo quando \(v\) aponta na direção do gradiente. Portanto, \(-\nabla f(w)\) é a direção de maior declive local.

5.4.17.8.1 Derivação com rótulos \(\{0,1\}\)

Para um exemplo, defina

\[ z_n=\widetilde x_n^{\mathsf T}\widetilde w, \qquad p_n=\sigma(z_n), \]

e use a perda estável nos logits

\[ \ell_n(\widetilde w) =\ln(1+e^{z_n})-y_nz_n. \]

Como a derivada da softplus é a sigmoide,

\[ \frac{\partial\ell_n}{\partial z_n} =\sigma(z_n)-y_n =p_n-y_n. \]

Além disso,

\[ \nabla_{\widetilde w}z_n=\widetilde x_n. \]

Pela regra da cadeia,

\[ \nabla_{\widetilde w}\ell_n =(p_n-y_n)\widetilde x_n. \tag{5.46}\]

Calculando a média e reunindo os exemplos na matriz de projeto,

\[ \nabla E(\widetilde w) =\frac1N\sum_{n=1}^{N}(p_n-y_n)\widetilde x_n =\frac1N\widetilde X^{\mathsf T}(p-y). \tag{5.47}\]

A fórmula possui uma interpretação simples: \(p-y\) mede o erro probabilístico de cada exemplo, e a multiplicação por \(\widetilde X^{\mathsf T}\) distribui esses erros entre os parâmetros de acordo com os valores dos atributos.

5.4.17.8.2 Derivação com rótulos \(\{-1,+1\}\)

Para \(t_n\in\{-1,+1\}\), a perda é

\[ \ell_n=\ln(1+e^{-t_nz_n}). \]

Sua derivada é

\[ \nabla_{\widetilde w}\ell_n =-t_n\sigma(-t_nz_n)\widetilde x_n =-\frac{t_n\widetilde x_n}{1+e^{t_nz_n}}. \tag{5.48}\]

Observe o expoente \(+t_nz_n\) no denominador. Quando a margem é grande e positiva, a contribuição tende a zero; quando é negativa, a contribuição aproxima-se de \(-t_n\widetilde x_n\).

5.4.17.8.3 Atualização em lote

O gradiente descendente em lote usa todos os exemplos:

\[ \widetilde w^{(k+1)} =\widetilde w^{(k)} -\eta_k \frac1N\widetilde X^{\mathsf T} \left(p^{(k)}-y\right). \tag{5.49}\]

Com regularização \(L_2\), adicionamos \(\lambda w\) às coordenadas dos pesos, deixando o intercepto sem penalidade.

Um passo muito pequeno converge lentamente. Um passo muito grande pode fazer a perda oscilar ou aumentar, apesar da convexidade. Convexidade descreve a forma do objetivo, não corrige automaticamente uma taxa de aprendizado inadequada.

5.4.17.8.4 Gradiente estocástico e minilotes

O gradiente completo custa \(O(Nd)\) por iteração. Para bases grandes, podemos estimá-lo usando um subconjunto \(B\):

\[ g_B(\widetilde w) =\frac1{|B|} \sum_{n\in B}(p_n-y_n)\widetilde x_n. \]

  • SGD: \(|B|=1\); atualizações baratas e ruidosas;
  • minilote: \(1<|B|<N\); aproveita vetorização e reduz variância;
  • lote completo: \(|B|=N\); direção determinística.

Em treinamento por minilotes, embaralhamos os exemplos a cada época e normalmente reduzimos a taxa de aprendizado ao longo do tempo. O ruído faz a perda oscilar, portanto um único aumento entre passos não implica falha.

5.4.17.8.5 Implementação estável
import numpy as np


def perda_e_gradiente_logistico(X, y, w, b, lambda_l2=0.0):
    z = X @ w + b

    # Perda diretamente nos logits: softplus(z) - y*z.
    perdas = np.logaddexp(0.0, z) - y * z
    perda = np.mean(perdas) + 0.5 * lambda_l2 * (w @ w)

    # Sigmoide estável.
    p = np.empty_like(z)
    positivos = z >= 0
    p[positivos] = 1 / (1 + np.exp(-z[positivos]))
    exp_z = np.exp(z[~positivos])
    p[~positivos] = exp_z / (1 + exp_z)

    erro = p - y
    grad_w = X.T @ erro / len(X) + lambda_l2 * w
    grad_b = np.mean(erro)
    return perda, grad_w, grad_b

Uma implementação do treinamento pode usar:

def ajustar_por_gradiente(
    X,
    y,
    *,
    taxa=0.1,
    max_iter=10_000,
    tolerancia=1e-7,
    lambda_l2=0.0,
):
    X = np.asarray(X, dtype=float)
    y = np.asarray(y, dtype=float)
    w = np.zeros(X.shape[1])
    b = 0.0
    historico = []

    for iteracao in range(1, max_iter + 1):
        perda, grad_w, grad_b = perda_e_gradiente_logistico(
            X, y, w, b, lambda_l2
        )
        norma_grad = np.sqrt(grad_w @ grad_w + grad_b**2)
        historico.append(perda)

        if not np.isfinite(perda):
            raise FloatingPointError("a perda deixou de ser finita")
        if norma_grad <= tolerancia:
            return w, b, historico, True

        w -= taxa * grad_w
        b -= taxa * grad_b

    return w, b, historico, False

O retorno booleano impede que atingir o limite de iterações seja confundido com convergência.

5.4.17.8.6 Verificação por diferenças finitas

Antes de confiar numa derivada implementada manualmente, podemos compará-la com uma aproximação numérica:

\[ \frac{\partial E}{\partial w_j} \approx \frac{E(w+\varepsilon e_j)-E(w-\varepsilon e_j)} {2\varepsilon}. \]

def gradiente_numerico(funcao, w, epsilon=1e-6):
    aproximacao = np.zeros_like(w)

    for j in range(len(w)):
        deslocamento = np.zeros_like(w)
        deslocamento[j] = epsilon
        aproximacao[j] = (
            funcao(w + deslocamento)
            - funcao(w - deslocamento)
        ) / (2 * epsilon)

    return aproximacao

Diferenças finitas também têm erro de arredondamento e truncamento, mas são excelentes para detectar sinais trocados, fatores ausentes e erros de transposição em exemplos pequenos.

5.4.17.8.7 Convergência e unicidade

A perda é convexa, mas o mínimo não é necessariamente único sem condições adicionais. Colunas redundantes produzem direções planas. Em dados perfeitamente separáveis e sem regularização, o ínfimo pode ser aproximado enquanto a norma dos parâmetros diverge, sem um minimizador finito.

Com regularização \(L_2\) positiva nas direções relevantes, o objetivo torna-se mais fortemente convexo e o comportamento numérico melhora.

TipMonitore mais que a perda

Registre norma do gradiente, perda de validação e norma dos parâmetros. Uma perda que muda pouco pode indicar convergência, taxa pequena demais ou saturação numérica; os outros sinais ajudam a distinguir os casos.

5.4.17.8.8 Exercícios
  1. Derive Equation 5.46 pela regra da cadeia.
  2. Converta Equation 5.48 para a codificação \(\{0,1\}\).
  3. Implemente a verificação por diferenças finitas para \(w\) e \(b\).
  4. Compare lote completo e minilotes na mesma amostra, usando a mesma quantidade de épocas.
  5. Explique por que padronizar atributos permite usar uma taxa comum com mais segurança.

5.4.17.9 Método de Newton

O gradiente usa a inclinação local, mas ignora como essa inclinação muda em cada direção. O método de Newton acrescenta a informação de curvatura contida na Hessiana.

5.4.17.9.1 Da aproximação quadrática ao passo

Perto de um ponto \(w\), a expansão de Taylor de segunda ordem é

\[ E(w+d) \approx E(w)+\nabla E(w)^{\mathsf T}d +\frac12d^{\mathsf T}H(w)d, \]

em que \(H(w)=\nabla^2E(w)\). Para minimizar essa aproximação quadrática em relação a \(d\), zeramos seu gradiente:

\[ \nabla E(w)+H(w)d=0. \]

A direção de Newton resolve, portanto,

\[ H(w)d=-\nabla E(w), \tag{5.50}\]

e a atualização é

\[ w_{\mathrm{novo}}=w+\eta d, \tag{5.51}\]

com \(\eta=1\) no Newton puro. Em código, resolvemos Equation 5.50; não calculamos \(H^{-1}\) explicitamente.

Em uma dimensão, essa expressão reduz a

\[ w_{\mathrm{novo}} =w-\frac{E'(w)}{E''(w)}, \]

que é o método de Newton aplicado à equação \(E'(w)=0\).

5.4.17.9.2 Gradiente e Hessiana logísticos

Para a matriz homogênea \(\widetilde X\), temos

\[ g=\nabla E(\widetilde w) =\frac1N\widetilde X^{\mathsf T}(p-y) \]

e

\[ H=\nabla^2E(\widetilde w) =\frac1N\widetilde X^{\mathsf T}S\widetilde X, \]

onde

\[ S=\operatorname{diag} \left(p_1(1-p_1),\ldots,p_N(1-p_N)\right). \]

A matriz \(S\) atribui peso maior aos exemplos cuja probabilidade está próxima de \(0{,}5\) e peso menor aos que estão saturados perto de zero ou um. Se houver regularização \(L_2\), adicionamos \(\lambda I\) às coordenadas penalizadas da Hessiana e \(\lambda w\) ao gradiente.

5.4.17.9.3 Relação com mínimos quadrados reponderados

A equação de Newton pode ser reescrita como um problema de mínimos quadrados iterativamente reponderados (IRLS). Defina a resposta de trabalho

\[ r =\widetilde X\widetilde w +S^{-1}(y-p). \]

O próximo vetor resolve

\[ \widetilde w_{\mathrm{novo}} =\operatorname*{arg\,min}_{v} \left\|S^{1/2}(r-\widetilde Xv)\right\|_2^2. \tag{5.52}\]

As equações normais de 2 são

\[ \widetilde X^{\mathsf T}S\widetilde X \widetilde w_{\mathrm{novo}} =\widetilde X^{\mathsf T}Sr, \]

que equivalem ao passo de Newton. O nome “reponderados” vem do fato de \(S\) mudar a cada iteração conforme mudam as probabilidades.

Na prática, não é necessário formar \(S\) como uma matriz \(N\times N\). Se \(s=p(1-p)\), multiplicar por \(S\) equivale a multiplicar cada linha ou componente pelo elemento correspondente de \(s\).

5.4.17.9.4 Implementação com Newton amortecido

O código abaixo reúne intercepto e pesos em um vetor homogêneo, inclui regularização apenas nos pesos e usa backtracking para evitar passos que aumentem a perda.

import numpy as np


def perda_logistica_logits(X, y, w, lambda_l2=0.0):
    z = X @ w
    perda_dados = np.mean(np.logaddexp(0.0, z) - y * z)
    return perda_dados + 0.5 * lambda_l2 * (w[1:] @ w[1:])


def ajustar_logistica_newton(
    X,
    y,
    *,
    lambda_l2=1e-6,
    max_iter=100,
    tolerancia=1e-8,
):
    X = np.asarray(X, dtype=float)
    y = np.asarray(y, dtype=float)
    Xh = np.column_stack([np.ones(len(X)), X])
    w = np.zeros(Xh.shape[1])
    penalidade = np.diag([0.0] + [lambda_l2] * X.shape[1])
    historico = []

    for iteracao in range(1, max_iter + 1):
        z = Xh @ w

        p = np.empty_like(z)
        positivos = z >= 0
        p[positivos] = 1 / (1 + np.exp(-z[positivos]))
        exp_z = np.exp(z[~positivos])
        p[~positivos] = exp_z / (1 + exp_z)

        g = Xh.T @ (p - y) / len(Xh) + penalidade @ w
        s = p * (1 - p)
        H = Xh.T @ (s[:, None] * Xh) / len(Xh) + penalidade

        norma_grad = np.linalg.norm(g)
        perda_atual = perda_logistica_logits(
            Xh, y, w, lambda_l2
        )
        historico.append(perda_atual)

        if norma_grad <= tolerancia:
            return w, historico, True

        try:
            direcao = np.linalg.solve(H, -g)
        except np.linalg.LinAlgError:
            direcao = np.linalg.lstsq(H, -g, rcond=None)[0]

        # Backtracking: aceite um passo que reduza a perda.
        passo = 1.0
        derivada_direcional = g @ direcao
        while passo > 1e-12:
            candidato = w + passo * direcao
            perda_nova = perda_logistica_logits(
                Xh, y, candidato, lambda_l2
            )
            if perda_nova <= (
                perda_atual + 1e-4 * passo * derivada_direcional
            ):
                break
            passo *= 0.5
        else:
            return w, historico, False

        w = candidato

    return w, historico, False

A condição usada no backtracking é uma forma da condição de Armijo. Ela exige redução suficiente, não apenas qualquer diminuição minúscula.

5.4.17.9.5 Por que adicionar amortecimento?

Longe do mínimo, a aproximação quadrática pode ser ruim. Uma Hessiana quase singular também pode produzir um passo enorme. Há três mecanismos comuns:

  • usar \(\eta<1\) por busca linear;
  • adicionar \(\mu I\) à Hessiana, como em métodos de região de confiança;
  • usar regularização estatística, que também melhora o condicionamento.

Newton com busca linear preserva a rapidez local sem presumir que todo passo unitário seja seguro.

5.4.17.9.6 Custo computacional

Se \(p=d+1\) é o número de parâmetros, calcular gradiente e Hessiana densa custa aproximadamente \(O(Np^2)\), e resolver o sistema custa \(O(p^3)\). A memória da Hessiana é \(O(p^2)\).

O gradiente descendente evita a Hessiana e custa aproximadamente \(O(Np)\) por iteração. Newton costuma usar menos iterações, mas cada uma é mais cara. Para muitos parâmetros, métodos quase-Newton como L-BFGS aproximam a curvatura sem armazenar a Hessiana completa.

5.4.17.9.7 Newton, Fisher scoring e IRLS

Em modelos lineares generalizados, Fisher scoring substitui a Hessiana observada pela informação de Fisher esperada. Para a regressão logística Bernoulli com ligação canônica, as matrizes relevantes coincidem na forma usual, e o algoritmo é frequentemente descrito tanto como Newton–Raphson quanto como IRLS.

5.4.17.9.8 Convergência local

Perto de um mínimo estrito, com Hessiana não singular e regularidade suficiente, Newton pode apresentar convergência quadrática: o erro é aproximadamente elevado ao quadrado de uma iteração para a seguinte. Essa é uma propriedade local. Ela não garante que uma inicialização arbitrária aceite sempre passos unitários nem resolve separação perfeita.

WarningProbabilidades saturadas exigem cuidado

Quando \(p_n\) está numericamente em zero ou um, \(p_n(1-p_n)\) pode se tornar zero e a Hessiana perde informação naquela observação. Regularização, cálculo estável e amortecimento ajudam; recortar probabilidades sem documentar pode mascarar o problema.

5.4.17.9.9 Verificações
  1. Confirme que \(g^{\mathsf T}d<0\) para uma direção de descida.
  2. Verifique que a perda aceita pelo backtracking não aumenta.
  3. Monitore o número de condição de \(H\).
  4. Compare o resultado com um otimizador de biblioteca.
  5. Teste uma base perfeitamente separável com e sem regularização.
5.4.17.9.10 Exercícios
  1. Derive a Hessiana a partir de Equation 5.47.
  2. Mostre a equivalência entre Equation 5.50 e
  3. Explique por que não devemos formar \(S\) explicitamente.
  4. Compare custos de uma iteração de Newton e de gradiente para \(N=10^6\) e \(p=100\).
  5. Modifique o código para penalizar também o intercepto e discuta por que essa não é a convenção usual.

5.4.17.10 Método do Máximo Declive

O método do máximo declive, ou gradiente descendente, escolhe em cada iteração a direção oposta ao gradiente. Para uma direção unitária \(v\), a derivada direcional é

\[ D_vE(w)=\nabla E(w)^{\mathsf T}v. \]

Pela desigualdade de Cauchy–Schwarz,

\[ -\|\nabla E(w)\|_2 \leq \nabla E(w)^{\mathsf T}v \leq \|\nabla E(w)\|_2. \]

O menor valor ocorre em

\[ v=-\frac{\nabla E(w)}{\|\nabla E(w)\|_2}. \]

Assim, na geometria euclidiana dos parâmetros, o gradiente negativo é a direção de queda local mais rápida. A atualização usual absorve a normalização na taxa de aprendizado:

\[ w^{(k+1)}=w^{(k)}-\eta_k\nabla E(w^{(k)}). \tag{5.53}\]

O gradiente aponta perpendicularmente às curvas de nível. Quando essas curvas são muito alongadas, a trajetória pode atravessar repetidamente o vale e formar um zigue-zague.

O máximo declive cruza as curvas de nível na direção perpendicular local, podendo oscilar em vales alongados.
5.4.17.10.1 “Mais íngreme” depende da escala

Se substituímos um atributo medido em metros pelo mesmo atributo em milímetros, a função preditiva pode representar a mesma relação, mas a geometria do espaço de parâmetros muda. Consequentemente, a direção euclidiana de máximo declive também muda. Padronização e pré-condicionamento reduzem esse problema.

Newton pode ser interpretado como um passo de gradiente corrigido pela curvatura:

\[ d_{\mathrm{Newton}}=-H^{-1}g. \]

Em vez de tratar todas as direções com a mesma escala, a Hessiana reescala o gradiente conforme a curvatura local.

5.4.17.10.2 Como escolher o tamanho do passo?

Há três abordagens comuns:

  • taxa fixa: simples, mas exige ajuste;
  • agenda de decaimento: reduz \(\eta_k\) ao longo das iterações;
  • busca linear: escolhe um passo que produza redução suficiente.

Para regressão logística sem regularização, a Hessiana satisfaz

\[ \nabla^2E(w) \preceq \frac{1}{4N}\widetilde X^{\mathsf T}\widetilde X, \]

pois \(p_n(1-p_n)\leq1/4\). Portanto, a menor constante de Lipschitz \(L_{\mathrm{grad}}\) satisfaz

\[ L_{\mathrm{grad}} \leq\frac{\|\widetilde X\|_2^2}{4N} =:L_{\mathrm{cota}}. \]

Com penalidade \(L_2\) de intensidade \(\lambda\), acrescentamos aproximadamente \(\lambda\) à cota nas direções penalizadas. Um passo \(\eta\leq1/L_{\mathrm{cota}}\) fornece uma escolha conservadora para redução monotônica no problema convexo e suave.

Calcular \(\|\widetilde X\|_2\) exatamente pode ser caro; busca linear ou estimativas são alternativas práticas.

5.4.17.10.3 Busca linear por backtracking

Se \(g=\nabla E(w)\) e \(d=-g\), a condição de Armijo aceita \(\eta\) quando

\[ E(w+\eta d) \leq E(w)+c\eta g^{\mathsf T}d, \qquad 0<c<1. \tag{5.54}\]

Como \(g^{\mathsf T}d=-\|g\|^2<0\), o lado direito exige uma redução proporcional ao passo e à inclinação.

def passo_backtracking(
    perda,
    w,
    gradiente,
    *,
    passo_inicial=1.0,
    contracao=0.5,
    armijo=1e-4,
):
    direcao = -gradiente
    valor = perda(w)
    derivada_direcional = gradiente @ direcao
    passo = passo_inicial

    while passo > 1e-12:
        candidato = w + passo * direcao
        if perda(candidato) <= (
            valor + armijo * passo * derivada_direcional
        ):
            return passo
        passo *= contracao

    raise RuntimeError("a busca linear não encontrou um passo")

A busca começa com um passo candidato e o reduz geometricamente. Ela realiza avaliações extras da perda, mas evita escolher previamente uma taxa adequada para toda a trajetória.

5.4.17.10.4 Algoritmo completo
inicialize w
repita:
    calcule perda E(w) e gradiente g
    se ||g|| satisfaz a tolerância: pare
    escolha η por taxa fixa, agenda ou busca linear
    w ← w − ηg
até atingir o limite de iterações

Para minilotes, a busca linear é menos direta porque a perda estimada é ruidosa. Nesse caso, agendas de taxa e otimizadores adaptativos são mais comuns.

5.4.17.10.5 Convergência

Convexidade garante que um ponto estacionário finito é global, mas não garante unicidade nem existência de minimizador finito em separação perfeita. Sob suavidade e um passo apropriado, o gradiente descendente converge. Para funções fortemente convexas, como frequentemente ocorre com regularização \(L_2\) e posto adequado, a convergência pode ser linear em função do número de iterações.

O termo “linear” aqui descreve a taxa de convergência geométrica do erro, não o fato de o modelo usar uma pontuação linear.

5.4.17.10.6 Máximo declive versus Newton
Aspecto Máximo declive Newton
derivadas gradiente gradiente e Hessiana
memória adicional \(O(d)\) \(O(d^2)\) para Hessiana densa
custo típico por iteração \(O(Nd)\) \(O(Nd^2+d^3)\)
sensibilidade à escala alta menor, pela correção de curvatura
uso com minilotes natural menos comum na forma exata
velocidade perto do ótimo mais lenta potencialmente quadrática
NoteDescida local, objetivo global

A direção \(-g\) é definida por uma aproximação local. A convexidade é o que permite relacionar essa movimentação local ao mínimo global, desde que o tamanho do passo e as demais condições sejam adequados.

5.4.17.10.7 Exercícios
  1. Use Cauchy–Schwarz para demonstrar a direção de máximo declive.
  2. Mostre que \(g^{\mathsf T}(-g)=-\|g\|^2\).
  3. Explique como multiplicar um atributo por \(1\,000\) altera o caminho do gradiente descendente.
  4. Implemente Equation 5.54 e registre quantas reduções de passo ocorrem por iteração.
  5. Compare uma taxa fixa, backtracking e Newton na mesma amostra.

5.4.18 Computação

Esta seção transforma as derivações anteriores em um fluxo computacional completo. O objetivo não é apenas obter um vetor de pesos, mas produzir um artefato reproduzível que preserve pré-processamento, parâmetros, limiar e informações de convergência.

Compararemos duas implementações didáticas:

  1. Newton amortecido, adequado a bases densas de dimensão moderada;
  2. gradiente descendente, simples e adaptável a grandes volumes de dados e minilotes.

Em aplicações reais, bibliotecas consolidadas oferecem métodos quase-Newton, regularização, ponderação de classes e verificações numéricas adicionais. Implementar do zero é útil para compreender o algoritmo, não para substituir automaticamente essas bibliotecas.

5.4.18.1 Contrato dos dados

Adotaremos

\[ X\in\mathbb R^{N\times d}, \qquad y\in\{0,1\}^N. \]

Cada linha de \(X\) é um exemplo; cada coluna é um atributo. Antes do ajuste, verificamos:

  • mesmo número de linhas em \(X\) e entradas em \(y\);
  • somente valores finitos;
  • exatamente dois rótulos, codificados como zero e um;
  • presença de exemplos suficientes para a avaliação planejada.

Valores ausentes exigem uma política explícita. Remover linhas, preencher valores ou criar indicadores de ausência são decisões de modelagem e devem ser ajustadas somente com os dados de treinamento.

5.4.18.2 Divisão e pré-processamento

Para classificação, a divisão deve preservar aproximadamente a proporção das classes quando possível. O fluxo correto é:

dados brutos
  ├─ treino → ajustar imputação/padronização → ajustar modelo
  ├─ validação → aplicar transformações do treino → escolher hiperparâmetros
  └─ teste → aplicar transformações do treino → avaliação final única

Padronização é particularmente útil para regularização e gradiente descendente. O intercepto não é padronizado nem normalmente penalizado.

5.4.18.3 Saídas de um treinamento

Uma rotina deve devolver mais que os coeficientes. Um resultado mínimo pode ser representado por:

from dataclasses import dataclass

import numpy as np


@dataclass
class ResultadoLogistico:
    pesos: np.ndarray
    intercepto: float
    convergiu: bool
    iteracoes: int
    motivo_parada: str
    perdas: list[float]
    normas_gradiente: list[float]

O motivo da parada diferencia convergência, limite de iterações, busca linear malsucedida e problema numérico. Silenciar essa diferença pode levar um sistema a publicar parâmetros incompletamente ajustados.

5.4.18.4 API de predição

Devemos separar pontuação, probabilidade e classe:

def pontuacao(X, pesos, intercepto):
    return np.asarray(X, dtype=float) @ pesos + intercepto


def probabilidade_positiva(X, pesos, intercepto):
    z = pontuacao(X, pesos, intercepto)
    p = np.empty_like(z)
    positivos = z >= 0
    p[positivos] = 1 / (1 + np.exp(-z[positivos]))
    exp_z = np.exp(z[~positivos])
    p[~positivos] = exp_z / (1 + exp_z)
    return p


def prever_classe(X, pesos, intercepto, limiar=0.5):
    if not 0 < limiar < 1:
        raise ValueError("o limiar deve estar entre zero e um")
    return (
        probabilidade_positiva(X, pesos, intercepto) >= limiar
    ).astype(int)

Essa separação impede que uma alteração de limiar seja confundida com novo treinamento e permite avaliar calibração usando as probabilidades.

5.4.18.5 Métricas complementares

A log-loss avalia probabilidades. Após escolher um limiar, a matriz de confusão permite calcular precisão e revocação:

\[ \operatorname{precisão}=\frac{VP}{VP+FP}, \qquad \operatorname{revocação}=\frac{VP}{VP+FN}. \]

Quando um denominador é zero, a implementação deve definir o comportamento em vez de produzir silenciosamente um valor enganoso. Para bases desbalanceadas, acurácia isolada pode ocultar falha completa na classe rara.

Também devemos inspecionar:

  • log-loss em treino, validação e teste;
  • curva ROC ou precisão–revocação, conforme a aplicação;
  • calibração das probabilidades;
  • métricas por subgrupo relevante;
  • estabilidade sob mudança temporal ou operacional.

5.4.18.6 Reprodutibilidade

Registre versão dos dados, divisão, semente, transformações, intensidade de regularização, algoritmo, tolerâncias e limite de iterações. Para os métodos determinísticos em lote apresentados aqui, a semente pode afetar a divisão dos dados, mesmo quando não afeta a otimização.

ImportantO conjunto de teste não escolhe o algoritmo

Comparar Newton, gradiente, regularização ou limiares repetidamente no teste transforma esse conjunto em validação. Escolha configurações na validação e use o teste apenas para a estimativa final.

5.4.18.7 Pelo Método de Newton

A forma computacional correta do passo de Newton é

\[ H_t d_t=-g_t, \qquad \widetilde w_{t+1} =\widetilde w_t+\eta_t d_t, \]

em que \(g_t\) e \(H_t\) são o gradiente e a Hessiana no estado atual. Observe o sinal negativo: somar \(H_t^{-1}g_t\) moveria, em geral, para a direção errada.

5.4.18.7.1 Pseudocódigo
entrada: X, y, λ, tolerâncias e limite de iterações
adicione a coluna de intercepto a X
inicialize w

para t = 0, 1, ...:
    z ← Xw
    p ← sigmoide_estável(z)
    g ← Xᵀ(p − y)/N + gradiente_da_penalidade
    H ← Xᵀ diag(p(1−p)) X/N + Hessiana_da_penalidade

    se ||g|| for suficientemente pequena:
        devolva convergência

    resolva H d = −g
    escolha η por backtracking
    w ← w + ηd

    se a variação relativa da perda for pequena:
        devolva convergência

devolva limite_de_iterações

O intercepto corresponde à primeira coordenada de \(w\). Para não penalizá-lo, usamos uma matriz diagonal de regularização cujo primeiro elemento é zero.

5.4.18.7.2 Inicialização

O vetor nulo é uma escolha válida e determinística. Nesse ponto, todas as probabilidades valem \(0{,}5\). Quando a classe positiva é rara, podemos inicializar apenas o intercepto com a prevalência suavizada:

\[ b_0 =\ln\left( \frac{n_1+\alpha}{n_0+\alpha} \right), \]

em que \(n_1\) e \(n_0\) são as contagens das classes e \(\alpha>0\) evita logaritmo de zero. Os pesos começam em zero.

Inicialização aleatória não é necessária para quebrar simetria em uma única regressão logística e dificulta reproduzir resultados sem oferecer benefício automático.

5.4.18.7.3 Solução do sistema

Nunca forme \(H^{-1}\). Resolva

direcao = np.linalg.solve(H, -gradiente)

Quando a matriz é simétrica positiva definida, uma fatoração de Cholesky é apropriada. Se o sistema estiver singular ou quase singular, verifique posto, escala, separação e regularização; recorrer silenciosamente à pseudoinversa pode ocultar um problema de modelagem.

O sistema também pode ser resolvido sem materializar a Hessiana em problemas grandes, usando produtos Hessiana–vetor e métodos como gradientes conjugados.

5.4.18.7.4 Critérios combinados

Uma implementação robusta pode declarar convergência quando pelo menos uma destas condições, devidamente escalada, é satisfeita:

\[ \|g_t\|_\infty \leq \varepsilon_g, \]

\[ \frac{|E_{t+1}-E_t|} {\max(1,|E_t|)} \leq\varepsilon_E, \]

\[ \frac{\|\widetilde w_{t+1}-\widetilde w_t\|_2} {\max(1,\|\widetilde w_t\|_2)} \leq\varepsilon_w. \]

O limite máximo permanece obrigatório. Uma perda “suficientemente pequena” não é um bom critério universal: com ruído, o ótimo pode estar longe de zero; em separação perfeita, perseguir perda quase zero pode fazer os coeficientes divergir.

5.4.18.7.5 Exemplo numérico

Considere um único atributo:

X = np.array([[-2.0], [-1.0], [0.5], [1.0], [2.0]])
y = np.array([0.0, 0.0, 0.0, 1.0, 1.0])

Com \(\lambda=0{,}1\) nos pesos e inicialização zero, Newton produz uma sequência como:

iteração perda penalizada norma do gradiente
0 \(0{,}6931\) \(0{,}5590\)
1 valor menor norma menor
2 aproximação refinada próxima de zero

Os valores exatos dependem da normalização da penalidade e da regra de passo. A propriedade importante é que cada passo aceito pelo backtracking reduz a função objetivo.

Podemos verificar a solução final por três condições:

z = Xh @ w_final
p = 1 / (1 + np.exp(-z))
gradiente = Xh.T @ (p - y) / len(Xh) + penalidade @ w_final

assert np.linalg.norm(gradiente) < 1e-6
assert all(
    atual <= anterior + 1e-12
    for anterior, atual in zip(perdas, perdas[1:])
)
assert np.all(np.isfinite(w_final))
5.4.18.7.6 Diagnóstico de falhas
Sintoma Causa provável Ação
sistema singular colunas redundantes ou pesos saturados verificar posto e regularizar
perda aumenta passo unitário inadequado ou erro no gradiente usar backtracking e checar derivadas
coeficientes crescem sem parar separação perfeita regularizar e monitorar norma
valor não finito na perda exponencial ou logaritmo instável trabalhar diretamente com logits
convergência lenta condicionamento ruim padronizar e revisar atributos
validação piora sobreajuste regularização e seleção por validação
5.4.18.7.7 Custo e escolha do método

Newton é atraente quando o número de parâmetros é moderado e a matriz cabe confortavelmente na memória. Se \(d\) for grande, armazenar e fatorar uma Hessiana densa pode dominar o custo. Nessa situação, L-BFGS, gradiente estocástico ou Newton truncado podem ser melhores.

TipCompare com uma implementação de referência

Em testes, compare probabilidades, perda e gradiente com uma biblioteca consolidada usando a mesma regularização e convenção de intercepto. Coeficientes podem diferir se as bibliotecas normalizam a penalidade de maneiras distintas.

5.4.18.7.8 Exercícios
  1. Corrija o pseudocódigo se a função objetivo for a soma, e não a média, das perdas.
  2. Implemente os três critérios relativos de parada.
  3. Force duas colunas idênticas e observe o sistema sem regularização.
  4. Compare inicialização nula e intercepto pela prevalência.
  5. Registre passo aceito, condição da Hessiana e norma dos pesos em cada iteração.

5.4.18.8 Pelo Método do Máximo Declive

A implementação em lote usa o gradiente completo

\[ g_t =\frac1N\widetilde X^{\mathsf T}(p_t-y) +\lambda R\widetilde w_t, \]

em que \(R=\operatorname{diag}(0,1,\ldots,1)\) deixa o intercepto sem penalidade. A atualização é

\[ \widetilde w_{t+1} =\widetilde w_t-\eta_tg_t. \]

Não normalizamos obrigatoriamente \(g_t\). Na forma \(-g_t/\|g_t\|\), todos os passos teriam comprimento \(\eta_t\), descartando a informação de que o gradiente pequeno pode indicar proximidade do ótimo. A versão não normalizada é a convenção mais comum.

5.4.18.8.1 Pseudocódigo
entrada: X, y, λ, taxa ou busca linear, tolerâncias, max_iter
adicione a coluna de intercepto
inicialize w

para t = 0, 1, ...:
    calcule perda E(w) e gradiente g
    registre perda e ||g||

    se ||g|| satisfaz a tolerância:
        devolva convergência

    escolha η
    candidato ← w − ηg

    se candidato não é finito:
        devolva falha numérica

    atualize w
    verifique variação relativa e limite de iterações

devolva o último estado com motivo da parada
5.4.18.8.2 Implementação em lote
import numpy as np


def objetivo_e_gradiente(Xh, y, w, lambda_l2):
    z = Xh @ w
    perda = np.mean(np.logaddexp(0.0, z) - y * z)
    perda += 0.5 * lambda_l2 * (w[1:] @ w[1:])

    p = np.empty_like(z)
    positivos = z >= 0
    p[positivos] = 1 / (1 + np.exp(-z[positivos]))
    exp_z = np.exp(z[~positivos])
    p[~positivos] = exp_z / (1 + exp_z)

    gradiente = Xh.T @ (p - y) / len(Xh)
    gradiente[1:] += lambda_l2 * w[1:]
    return perda, gradiente


def ajustar_logistica_gradiente(
    X,
    y,
    *,
    lambda_l2=1e-4,
    taxa=0.1,
    max_iter=10_000,
    tolerancia_grad=1e-7,
    tolerancia_perda=1e-10,
):
    X = np.asarray(X, dtype=float)
    y = np.asarray(y, dtype=float)
    Xh = np.column_stack([np.ones(len(X)), X])
    w = np.zeros(Xh.shape[1])
    perdas = []
    normas = []
    perda_anterior = None

    for iteracao in range(1, max_iter + 1):
        perda, gradiente = objetivo_e_gradiente(
            Xh, y, w, lambda_l2
        )
        norma = np.linalg.norm(gradiente)
        perdas.append(float(perda))
        normas.append(float(norma))

        if not np.isfinite(perda) or not np.all(
            np.isfinite(gradiente)
        ):
            motivo = "valor não finito"
            break

        if norma <= tolerancia_grad:
            motivo = "norma do gradiente"
            return w, perdas, normas, True, motivo

        if perda_anterior is not None:
            variacao = abs(perda - perda_anterior)
            escala = max(1.0, abs(perda_anterior))
            if variacao / escala <= tolerancia_perda:
                motivo = "variação relativa da perda"
                return w, perdas, normas, True, motivo

        w -= taxa * gradiente
        perda_anterior = perda
    else:
        motivo = "limite de iterações"

    return w, perdas, normas, False, motivo

Essa versão usa taxa fixa. Ela é apropriada para estudo, mas deve verificar se a perda realmente diminui. Podemos substituir a linha de atualização pela busca de Armijo apresentada anteriormente.

5.4.18.8.3 Validação das entradas

Antes do treinamento, acrescente verificações:

def validar_classificacao_binaria(X, y):
    if X.ndim != 2:
        raise ValueError("X deve ser bidimensional")
    if y.ndim != 1 or len(X) != len(y):
        raise ValueError("y deve ter um rótulo por exemplo")
    if len(X) == 0:
        raise ValueError("a amostra não pode ser vazia")
    if not np.all(np.isfinite(X)) or not np.all(np.isfinite(y)):
        raise ValueError("os dados devem ser finitos")
    if not np.all(np.isin(y, (0, 1))):
        raise ValueError("os rótulos devem pertencer a {0, 1}")

Uma amostra contendo apenas uma classe ainda pode ser aceita matematicamente, mas exige interpretação cuidadosa e geralmente não permite avaliação discriminativa útil.

5.4.18.8.4 Exemplo reproduzível
X = np.array([
    [-2.0,  0.2],
    [-1.5, -0.4],
    [-0.5,  0.3],
    [ 0.4, -0.2],
    [ 1.0,  0.5],
    [ 1.8, -0.1],
])
y = np.array([0, 0, 0, 1, 1, 1], dtype=float)

w_homogeneo, perdas, normas, convergiu, motivo = (
    ajustar_logistica_gradiente(
        X,
        y,
        lambda_l2=0.01,
        taxa=0.2,
        max_iter=5_000,
    )
)

intercepto = w_homogeneo[0]
pesos = w_homogeneo[1:]
probabilidades = probabilidade_positiva(
    X, pesos, intercepto
)

print("convergiu:", convergiu, "-", motivo)
print("perda inicial/final:", perdas[0], perdas[-1])
print("probabilidades:", probabilidades)

Verificações úteis:

assert np.all(np.isfinite(w_homogeneo))
assert perdas[-1] <= perdas[0]
assert np.all((probabilidades >= 0) & (probabilidades <= 1))

Comparar apenas a perda final com a inicial é uma condição fraca: uma execução pode terminar melhor que começou e ainda oscilar muito. Para taxa fixa em lote, inspecione toda a sequência ou use busca linear.

5.4.18.8.5 Minilotes

Para minilotes, selecione índices, calcule o gradiente apenas no bloco e atualize imediatamente:

rng = np.random.default_rng(42)

for epoca in range(max_epocas):
    indices = rng.permutation(len(Xh))

    for inicio in range(0, len(Xh), tamanho_lote):
        lote = indices[inicio:inicio + tamanho_lote]
        _, gradiente = objetivo_e_gradiente(
            Xh[lote], y[lote], w, lambda_l2
        )
        w -= taxa * gradiente

Há uma sutileza na regularização: se a função de lote adiciona a penalidade completa em cada minilote, a quantidade efetiva de regularização por época depende do número de lotes e da convenção de taxa. Bibliotecas definem cuidadosamente a normalização; ao comparar implementações, confira se \(\lambda\) possui o mesmo significado.

5.4.18.8.6 Monitoramento

Um gráfico útil contém perda de treino e validação por época. Há três padrões típicos:

  • ambas diminuem: o ajuste ainda melhora;
  • treino diminui e validação aumenta: possível sobreajuste;
  • ambas oscilam ou divergem: taxa alta, dados mal escalados ou erro de implementação.

Parada antecipada escolhe o estado de menor perda de validação, não necessariamente o último. Como no Pocket, é preciso copiar os parâmetros ao guardar o melhor estado.

5.4.18.8.7 Escolha do limiar

O treinamento da log-loss não determina automaticamente o limiar de decisão. Depois de ajustar o modelo:

  1. gere probabilidades na validação;
  2. avalie candidatos a limiar segundo o custo ou métrica desejada;
  3. fixe o limiar;
  4. avalie uma única vez no teste.

Se o custo de falso positivo é \(C_{FP}\) e o de falso negativo é \(C_{FN}\), sob condições simples e probabilidades calibradas, a decisão de menor custo prevê positivo quando

\[ p(x)\geq \frac{C_{FP}}{C_{FP}+C_{FN}}. \]

Custos, prevalência e ações reais precisam ser definidos com os responsáveis pela aplicação.

5.4.18.8.8 Comparação final dos métodos
Critério Newton amortecido Gradiente em lote
parâmetros moderados geralmente eficiente funciona, com mais iterações
muitos atributos Hessiana pode ser proibitiva memória menor
taxa de aprendizado busca de passo ainda útil escolha central
curvatura usada explicitamente ignorada
minilotes não natural na forma exata natural
implementação mais complexa mais simples
diagnóstico essencial condição da Hessiana escala e taxa
5.4.18.8.9 Recapitulação da regressão logística
  1. A pontuação linear modela log-odds.
  2. A sigmoide converte pontuação em probabilidade.
  3. A entropia cruzada vem da verossimilhança Bernoulli.
  4. O gradiente é \(\widetilde X^{\mathsf T}(p-y)/N\).
  5. A Hessiana é \(\widetilde X^{\mathsf T}S\widetilde X/N\).
  6. Regularização controla coeficientes e melhora condicionamento.
  7. Probabilidade, classe e ação são saídas conceitualmente distintas.
  8. Convergência de treino não substitui validação, calibração e análise por subgrupo.
ImportantDo modelo ao sistema

Um classificador em produção inclui dados, transformação, parâmetros, calibração, limiar, tratamento de entradas inválidas e monitoramento. Salvar apenas o vetor de pesos não preserva o comportamento completo.

5.4.18.8.10 Exercícios integradores
  1. Execute Newton e gradiente na mesma divisão e compare perdas, iterações e tempo.
  2. Produza uma amostra separável e observe os coeficientes sem regularização.
  3. Selecione um limiar que maximize revocação sob uma precisão mínima.
  4. Construa um diagrama de calibração em dez faixas de probabilidade.
  5. Simule mudança de prevalência no teste e observe acurácia, precisão, revocação e calibração.
  6. Explique por que escolher o limiar no teste invalida sua função de avaliação final.

5.5 Exercícios de múltipla escolha

Assinale uma alternativa em cada questão e confira depois as justificativas.

  1. No perceptron com rótulos \(y\in\{-1,+1\}\), um exemplo está corretamente classificado quando:

    1. \(y(\mathbf{w}^{\mathsf T}\mathbf{x}+b)>0\).
    2. \(y(\mathbf{w}^{\mathsf T}\mathbf{x}+b)<0\).
    3. \(\mathbf{w}=\mathbf{0}\) para qualquer entrada.
    4. \(b\) é necessariamente positivo.
  2. Ao encontrar um exemplo mal classificado, a atualização básica do perceptron para os pesos é:

    1. \(\mathbf{w}\leftarrow\mathbf{w}-\eta y\mathbf{x}\).
    2. \(\mathbf{w}\leftarrow\mathbf{w}+\eta y\mathbf{x}\).
    3. \(\mathbf{w}\leftarrow\eta\mathbf{w}^2\).
    4. \(\mathbf{w}\leftarrow\mathbf{x}-y\).
  3. O teorema de convergência do perceptron garante término em número finito de atualizações quando os dados são:

    1. linearmente separáveis com margem positiva.
    2. sempre não separáveis.
    3. produzidos por regressão.
    4. normalizados, independentemente dos rótulos.
  4. O algoritmo Pocket é útil principalmente porque:

    1. transforma qualquer problema em separável.
    2. guarda a melhor solução observada durante a execução.
    3. calcula probabilidades perfeitamente calibradas.
    4. dispensa um critério de parada.
  5. Na regressão linear por mínimos quadrados, a condição de ortogonalidade dos resíduos é:

    1. \(X^{\mathsf T}(X\mathbf{w}-\mathbf{y})=\mathbf{0}\).
    2. \(X\mathbf{y}=\mathbf{0}\).
    3. \(\mathbf{w}^{\mathsf T}\mathbf{w}=0\).
    4. \(X^{\mathsf T}X=0\).
  6. Por que solve ou uma fatoração QR costuma ser preferível a calcular explicitamente \((X^{\mathsf T}X)^{-1}\)?

    1. Porque evita toda multiplicação.
    2. Porque tende a oferecer maior estabilidade numérica.
    3. Porque elimina a necessidade de dados.
    4. Porque sempre produz coeficientes inteiros.
  7. O coeficiente de determinação \(R^2\) compara o erro do modelo com:

    1. um preditor de referência baseado na média da saída.
    2. a quantidade de classes.
    3. o maior valor singular de \(X\).
    4. o erro de classificação zero–um.
  8. A função logística transforma uma pontuação real em um valor no intervalo:

    1. \((-\infty,+\infty)\).
    2. \([-1,1]\).
    3. \((0,1)\).
    4. \([0,+\infty)\).
  9. Na regressão logística binária, escolher um limiar de decisão diferente de \(0{,}5\):

    1. é impossível matematicamente.
    2. pode alterar o compromisso entre falsos positivos e falsos negativos.
    3. modifica obrigatoriamente os pesos já treinados.
    4. torna todas as probabilidades iguais.
  10. Em comparação com o máximo declive, o método de Newton utiliza:

    1. somente o sinal dos rótulos.
    2. informação de segunda ordem por meio da Hessiana.
    3. uma taxa de aprendizado sempre igual a zero.
    4. apenas uma observação do conjunto.
  1. a. O produto positivo indica que a pontuação possui o mesmo sinal do rótulo.
  2. b. A parcela \(\eta y\mathbf{x}\) desloca a pontuação do exemplo na direção correta.
  3. a. Separabilidade com margem sustenta a cota de atualizações; isso não é garantia de generalização.
  4. b. Em dados não separáveis, os pesos correntes podem piorar; o Pocket preserva a melhor configuração encontrada.
  5. a. Nas equações normais, o resíduo é ortogonal ao espaço coluna de \(X\).
  6. b. Formar a inversa e as equações normais pode ampliar erros de ponto flutuante e piorar o condicionamento.
  7. a. \(R^2\) mede a redução relativa da soma de quadrados frente à previsão constante pela média.
  8. c. Para toda entrada real finita, a sigmoide produz valor estritamente entre 0 e 1.
  9. b. O limiar converte probabilidade em ação e deve refletir custos e requisitos da aplicação.
  10. b. A Hessiana descreve a curvatura local e permite construir um passo de Newton.